Merge "SurfaceFlinger: Emit callbacks for non-buffer layer transactions"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index e3c4ede..01c4723 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -265,6 +265,22 @@
chmod 0666 /sys/kernel/tracing/per_cpu/cpu14/trace
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu15/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu15/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu16/trace
+ chmod 0666 /sys/kernel/tracing/per_cpu/cpu16/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu17/trace
+ chmod 0666 /sys/kernel/tracing/per_cpu/cpu17/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu18/trace
+ chmod 0666 /sys/kernel/tracing/per_cpu/cpu18/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu19/trace
+ chmod 0666 /sys/kernel/tracing/per_cpu/cpu19/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu20/trace
+ chmod 0666 /sys/kernel/tracing/per_cpu/cpu20/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu21/trace
+ chmod 0666 /sys/kernel/tracing/per_cpu/cpu21/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu22/trace
+ chmod 0666 /sys/kernel/tracing/per_cpu/cpu22/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu23/trace
+ chmod 0666 /sys/kernel/tracing/per_cpu/cpu23/trace
# Only create the tracing instance if persist.mm_events.enabled
# Attempting to remove the tracing instance after it has been created
@@ -337,6 +353,22 @@
chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu14/trace
chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu15/trace
chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu15/trace
+ chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu16/trace
+ chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu16/trace
+ chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu17/trace
+ chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu17/trace
+ chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu18/trace
+ chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu18/trace
+ chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu19/trace
+ chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu19/trace
+ chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu20/trace
+ chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu20/trace
+ chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu21/trace
+ chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu21/trace
+ chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu22/trace
+ chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu22/trace
+ chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu23/trace
+ chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu23/trace
on property:persist.debug.atrace.boottrace=1
start boottrace
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 83e6787..3722383 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -38,11 +38,6 @@
#include "DumpPool.h"
#include "TaskQueue.h"
-// Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
-// std::vector<std::string>
-// TODO: remove once not used
-#define MAX_ARGS_ARRAY_SIZE 1000
-
// TODO: move everything under this namespace
// TODO: and then remove explicitly android::os::dumpstate:: prefixes
namespace android {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 5082eb0..39ef0b5 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -25,6 +25,7 @@
#include <functional>
#include <inttypes.h>
#include <regex>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
@@ -281,36 +282,31 @@
}
status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
- auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
const binder::Status dump_permission = checkPermission(kDump);
if (!dump_permission.isOk()) {
- out << dump_permission.toString8() << endl;
+ dprintf(fd, "%s\n", dump_permission.toString8().c_str());
return PERMISSION_DENIED;
}
- std::lock_guard<std::recursive_mutex> lock(mLock);
- out << "installd is happy!" << endl;
+ std::lock_guard<std::recursive_mutex> lock(mLock);
{
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
- out << endl << "Storage mounts:" << endl;
+ dprintf(fd, "Storage mounts:\n");
for (const auto& n : mStorageMounts) {
- out << " " << n.first << " = " << n.second << endl;
+ dprintf(fd, " %s = %s\n", n.first.c_str(), n.second.c_str());
}
}
{
std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
- out << endl << "Per-UID cache quotas:" << endl;
+ dprintf(fd, "Per-UID cache quotas:\n");
for (const auto& n : mCacheQuotas) {
- out << " " << n.first << " = " << n.second << endl;
+ dprintf(fd, " %d = %" PRId64 "\n", n.first, n.second);
}
}
- out << "is_dexopt_blocked:" << android::installd::is_dexopt_blocked() << endl;
-
- out << endl;
- out.flush();
+ dprintf(fd, "is_dexopt_blocked:%d\n", android::installd::is_dexopt_blocked());
return NO_ERROR;
}
@@ -426,9 +422,131 @@
return true;
}
+static bool chown_app_dir(const std::string& path, uid_t uid, uid_t previousUid, gid_t cacheGid) {
+ FTS* fts;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
+ return false;
+ }
+ for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+ if (p->fts_info == FTS_D && p->fts_level == 1
+ && (strcmp(p->fts_name, "cache") == 0
+ || strcmp(p->fts_name, "code_cache") == 0)) {
+ // Mark cache dirs
+ p->fts_number = 1;
+ } else {
+ // Inherit parent's number
+ p->fts_number = p->fts_parent->fts_number;
+ }
+
+ switch (p->fts_info) {
+ case FTS_D:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (p->fts_statp->st_uid == previousUid) {
+ if (lchown(p->fts_path, uid, p->fts_number ? cacheGid : uid) != 0) {
+ PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+ }
+ } else {
+ LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected UID "
+ << p->fts_statp->st_uid << " instead of " << previousUid;
+ }
+ break;
+ }
+ }
+ fts_close(fts);
+ return true;
+}
+
+static void chown_app_profile_dir(const std::string &packageName, int32_t appId, int32_t userId) {
+ uid_t uid = multiuser_get_uid(userId, appId);
+ gid_t sharedGid = multiuser_get_shared_gid(userId, appId);
+
+ const std::string profile_dir =
+ create_primary_current_profile_package_dir_path(userId, packageName);
+ char *argv[] = { (char*) profile_dir.c_str(), nullptr };
+ if (FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr)) {
+ for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+ switch (p->fts_info) {
+ case FTS_D:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (lchown(p->fts_path, uid, uid) != 0) {
+ PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+ }
+ break;
+ }
+ }
+ fts_close(fts);
+ }
+
+ const std::string ref_profile_path =
+ create_primary_reference_profile_package_dir_path(packageName);
+ argv[0] = (char *) ref_profile_path.c_str();
+ if (FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr)) {
+ for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+ if (p->fts_info == FTS_D && p->fts_level == 0) {
+ if (chown(p->fts_path, AID_SYSTEM, sharedGid) != 0) {
+ PLOG(WARNING) << "Failed to chown " << p->fts_path;
+ }
+ continue;
+ }
+ switch (p->fts_info) {
+ case FTS_D:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (lchown(p->fts_path, sharedGid, sharedGid) != 0) {
+ PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+ }
+ break;
+ }
+ }
+ fts_close(fts);
+ }
+}
+
+static binder::Status createAppDataDirs(const std::string& path,
+ int32_t uid, int32_t* previousUid, int32_t cacheGid,
+ const std::string& seInfo, mode_t targetMode) {
+ struct stat st{};
+ bool existing = (stat(path.c_str(), &st) == 0);
+ if (existing) {
+ 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)) {
+ return error("Failed to chown " + path);
+ }
+ }
+ }
+
+ if (prepare_app_dir(path, targetMode, uid) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+ return error("Failed to prepare " + path);
+ }
+
+ // Consider restorecon over contents if label changed
+ if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
+ restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
+ restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
+ return error("Failed to restorecon " + path);
+ }
+
+ return ok();
+}
+
binder::Status InstalldNativeService::createAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
- const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
+ int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion,
+ int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -441,6 +559,14 @@
if (_aidl_return != nullptr) *_aidl_return = -1;
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);
+
int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
@@ -451,19 +577,13 @@
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
- bool existing = (access(path.c_str(), F_OK) == 0);
- if (prepare_app_dir(path, targetMode, uid) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
- return error("Failed to prepare " + path);
+ auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+ if (!status.isOk()) {
+ return status;
}
-
- // Consider restorecon over contents if label changed
- if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
- return error("Failed to restorecon " + path);
+ if (previousUid != uid) {
+ chown_app_profile_dir(packageName, appId, userId);
}
// Remember inode numbers of cache directories so that we can clear
@@ -485,19 +605,10 @@
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- bool existing = (access(path.c_str(), F_OK) == 0);
- if (prepare_app_dir(path, targetMode, uid) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
- return error("Failed to prepare " + path);
- }
-
- // Consider restorecon over contents if label changed
- if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
- return error("Failed to restorecon " + path);
+ auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+ if (!status.isOk()) {
+ return status;
}
if (!prepare_app_profile_dir(packageName, appId, userId)) {
@@ -507,7 +618,6 @@
return ok();
}
-
binder::Status InstalldNativeService::createAppData(
const android::os::CreateAppDataArgs& args,
android::os::CreateAppDataResult* _aidl_return) {
@@ -516,7 +626,7 @@
int64_t ceDataInode = -1;
auto status = createAppData(args.uuid, args.packageName, args.userId, args.flags, args.appId,
- args.seInfo, args.targetSdkVersion, &ceDataInode);
+ args.previousAppId, args.seInfo, args.targetSdkVersion, &ceDataInode);
_aidl_return->ceDataInode = ceDataInode;
_aidl_return->exceptionCode = status.exceptionCode();
_aidl_return->exceptionMessage = status.exceptionMessage();
@@ -530,7 +640,7 @@
std::lock_guard<std::recursive_mutex> lock(mLock);
std::vector<android::os::CreateAppDataResult> results;
- for (auto arg : args) {
+ for (const auto &arg : args) {
android::os::CreateAppDataResult result;
createAppData(arg, &result);
results.push_back(result);
@@ -628,14 +738,11 @@
}
}
if (flags & FLAG_STORAGE_DE) {
- std::string suffix = "";
- bool only_cache = false;
+ std::string suffix;
if (flags & FLAG_CLEAR_CACHE_ONLY) {
suffix = CACHE_DIR_POSTFIX;
- only_cache = true;
} else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
suffix = CODE_CACHE_DIR_POSTFIX;
- only_cache = true;
}
auto path = create_data_user_de_package_path(uuid_, userId, pkgname) + suffix;
@@ -1230,7 +1337,7 @@
}
if (!createAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE, appId,
- seInfo, targetSdkVersion, nullptr).isOk()) {
+ /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr).isOk()) {
res = error("Failed to create package target");
goto fail;
}
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index ae257df..8cfda01 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -47,7 +47,8 @@
binder::Status createAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
- const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return);
+ int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion,
+ int64_t* _aidl_return);
binder::Status createAppData(
const android::os::CreateAppDataArgs& args,
diff --git a/cmds/installd/binder/android/os/CreateAppDataArgs.aidl b/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
index 96d7faa..d5e8ee5 100644
--- a/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
+++ b/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
@@ -23,6 +23,7 @@
int userId;
int flags;
int appId;
+ int previousAppId;
@utf8InCpp String seInfo;
int targetSdkVersion;
}
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index ea26955..a937436 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -287,6 +287,7 @@
kTestUserId,
kAppDataFlags,
kTestAppUid,
+ 0 /* previousAppId */,
se_info_,
kOSdkVersion,
&ce_data_inode_);
@@ -1257,6 +1258,7 @@
kTestUserId,
kAppDataFlags,
kTestAppUid,
+ 0 /* previousAppId */,
se_info_,
kOSdkVersion,
&ce_data_inode_));
@@ -1320,6 +1322,7 @@
kTestUserId,
kAppDataFlags,
kTestAppUid,
+ 0 /* previousAppId */,
se_info_,
kOSdkVersion,
&ce_data_inode));
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.rc b/cmds/rss_hwm_reset/rss_hwm_reset.rc
index fbbc820..271cbf8 100644
--- a/cmds/rss_hwm_reset/rss_hwm_reset.rc
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.rc
@@ -18,7 +18,7 @@
oneshot
user nobody
group nobody readproc
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
capabilities DAC_OVERRIDE
on property:sys.rss_hwm_reset.on=1
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 0b00c2d..fe417a3 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -45,38 +45,14 @@
}
}
-// get the name of the generic interface we hold a reference to
-static String16 get_interface_name(sp<IBinder> service)
-{
- if (service != nullptr) {
- Parcel data, reply;
- data.markForBinder(service);
- status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
- if (err == NO_ERROR) {
- return reply.readString16();
- }
- }
- return String16();
-}
-
-static String8 good_old_string(const String16& src)
-{
- String8 name8;
- char ch8[2];
- ch8[1] = 0;
- for (unsigned j = 0; j < src.size(); j++) {
- char16_t ch = src[j];
- if (ch < 128) ch8[0] = (char)ch;
- name8.append(ch8);
- }
- return name8;
-}
-
int main(int argc, char* const argv[])
{
bool wantsUsage = false;
int result = 0;
+ /* Strip path off the program name. */
+ char* prog_name = basename(argv[0]);
+
while (1) {
int ic = getopt(argc, argv, "h?");
if (ic < 0)
@@ -88,7 +64,7 @@
wantsUsage = true;
break;
default:
- aerr << "service: Unknown option -" << ic << endl;
+ aerr << prog_name << ": Unknown option -" << ic << endl;
wantsUsage = true;
result = 10;
break;
@@ -103,7 +79,7 @@
sp<IServiceManager> sm = defaultServiceManager();
fflush(stdout);
if (sm == nullptr) {
- aerr << "service: Unable to get default service manager!" << endl;
+ aerr << prog_name << ": Unable to get default service manager!" << endl;
return 20;
}
@@ -117,7 +93,7 @@
aout << "Service " << argv[optind] <<
(service == nullptr ? ": not found" : ": found") << endl;
} else {
- aerr << "service: No service specified for check" << endl;
+ aerr << prog_name << ": No service specified for check" << endl;
wantsUsage = true;
result = 10;
}
@@ -129,8 +105,8 @@
String16 name = services[i];
sp<IBinder> service = sm->checkService(name);
aout << i
- << "\t" << good_old_string(name)
- << ": [" << good_old_string(get_interface_name(service)) << "]"
+ << "\t" << name
+ << ": [" << (service ? service->getInterfaceDescriptor() : String16()) << "]"
<< endl;
}
} else if (strcmp(argv[optind], "call") == 0) {
@@ -138,7 +114,7 @@
if (optind+1 < argc) {
int serviceArg = optind;
sp<IBinder> service = sm->checkService(String16(argv[optind++]));
- String16 ifName = get_interface_name(service);
+ String16 ifName = (service ? service->getInterfaceDescriptor() : String16());
int32_t code = atoi(argv[optind++]);
if (service != nullptr && ifName.size() > 0) {
Parcel data, reply;
@@ -152,7 +128,7 @@
if (strcmp(argv[optind], "i32") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no integer supplied for 'i32'" << endl;
+ aerr << prog_name << ": no integer supplied for 'i32'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -161,7 +137,7 @@
} else if (strcmp(argv[optind], "i64") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no integer supplied for 'i64'" << endl;
+ aerr << prog_name << ": no integer supplied for 'i64'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -170,7 +146,7 @@
} else if (strcmp(argv[optind], "s16") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no string supplied for 's16'" << endl;
+ aerr << prog_name << ": no string supplied for 's16'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -179,7 +155,7 @@
} else if (strcmp(argv[optind], "f") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no number supplied for 'f'" << endl;
+ aerr << prog_name << ": no number supplied for 'f'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -188,7 +164,7 @@
} else if (strcmp(argv[optind], "d") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no number supplied for 'd'" << endl;
+ aerr << prog_name << ": no number supplied for 'd'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -200,7 +176,7 @@
} else if (strcmp(argv[optind], "fd") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no path supplied for 'fd'" << endl;
+ aerr << prog_name << ": no path supplied for 'fd'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -208,7 +184,7 @@
const char *path = argv[optind++];
int fd = open(path, O_RDONLY);
if (fd < 0) {
- aerr << "service: could not open '" << path << "'" << endl;
+ aerr << prog_name << ": could not open '" << path << "'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -217,7 +193,7 @@
} else if (strcmp(argv[optind], "afd") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no path supplied for 'afd'" << endl;
+ aerr << prog_name << ": no path supplied for 'afd'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -226,7 +202,8 @@
int fd = open(path, O_RDONLY);
struct stat statbuf;
if (fd < 0 || fstat(fd, &statbuf) != 0) {
- aerr << "service: could not open or stat '" << path << "'" << endl;
+ aerr << prog_name << ": could not open or stat"
+ << " '" << path << "'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -240,7 +217,8 @@
} else if (strcmp(argv[optind], "nfd") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no file descriptor supplied for 'nfd'" << endl;
+ aerr << prog_name << ": no file descriptor supplied for"
+ << " 'nfd'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -327,7 +305,7 @@
// for now just set the extra field to be null.
data.writeInt32(-1);
} else {
- aerr << "service: unknown option " << argv[optind] << endl;
+ aerr << prog_name << ": unknown option " << argv[optind] << endl;
wantsUsage = true;
result = 10;
break;
@@ -337,44 +315,44 @@
service->transact(code, data, &reply);
aout << "Result: " << reply << endl;
} else {
- aerr << "service: Service " << argv[serviceArg]
+ aerr << prog_name << ": Service " << argv[serviceArg]
<< " does not exist" << endl;
result = 10;
}
} else {
if (optind < argc) {
- aerr << "service: No service specified for call" << endl;
+ aerr << prog_name << ": No service specified for call" << endl;
} else {
- aerr << "service: No code specified for call" << endl;
+ aerr << prog_name << ": No code specified for call" << endl;
}
wantsUsage = true;
result = 10;
}
} else {
- aerr << "service: Unknown command " << argv[optind] << endl;
+ aerr << prog_name << ": Unknown command " << argv[optind] << endl;
wantsUsage = true;
result = 10;
}
}
if (wantsUsage) {
- aout << "Usage: service [-h|-?]\n"
- " service list\n"
- " service check SERVICE\n"
- " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null"
- " | fd f | nfd n | afd f ] ...\n"
+ aout << "Usage: " << prog_name << " [-h|-?]\n"
+ " " << prog_name << " list\n"
+ " " << prog_name << " check SERVICE\n"
+ " " << prog_name << " call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR"
+ " | null | fd f | nfd n | afd f ] ...\n"
"Options:\n"
" i32: Write the 32-bit integer N into the send parcel.\n"
" i64: Write the 64-bit integer N into the send parcel.\n"
- " f: Write the 32-bit single-precision number N into the send parcel.\n"
- " d: Write the 64-bit double-precision number N into the send parcel.\n"
+ " f: Write the 32-bit single-precision number N into the send parcel.\n"
+ " d: Write the 64-bit double-precision number N into the send parcel.\n"
" s16: Write the UTF-16 string STR into the send parcel.\n"
" null: Write a null binder into the send parcel.\n"
- " fd: Write a file descriptor for the file f to the send parcel.\n"
- " nfd: Write file descriptor n to the send parcel.\n"
- " afd: Write an ashmem file descriptor for a region containing the data from"
- " file f to the send parcel.\n";
-// " intent: Write and Intent int the send parcel. ARGS can be\n"
+ " fd: Write a file descriptor for the file f into the send parcel.\n"
+ " nfd: Write the file descriptor n into the send parcel.\n"
+ " afd: Write an ashmem file descriptor for a region containing the data from\n"
+ " file f into the send parcel.\n";
+// " intent: Write an Intent into the send parcel. ARGS can be\n"
// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
return result;
}
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 6d5070f..0dd29e0 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -9,5 +9,5 @@
onrestart class_restart main
onrestart class_restart hal
onrestart class_restart early_hal
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
shutdown critical
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index 756f6c3..c9305a1 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -2,7 +2,7 @@
class core
user system
group system readproc
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
onrestart class_restart main
onrestart class_restart hal
onrestart class_restart early_hal
diff --git a/include/android/input.h b/include/android/input.h
index 6d2c1b3..27587ce 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -1385,6 +1385,14 @@
*/
void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
+/**
+ * Supplies the AInputQueue* object associated with the supplied Java InputQueue
+ * object.
+ *
+ * Available since API level 33.
+ */
+AInputQueue* AInputQueue_fromJava(jobject inputQueue) __INTRODUCED_IN(33);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/binder/Enum.h b/include/binder/Enum.h
deleted file mode 100644
index 4c25654..0000000
--- a/include/binder/Enum.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#error Do not rely on global include files. All Android cc_* programs are given access to \
- include_dirs for frameworks/native/include via global configuration, but this is legacy \
- configuration. Instead, you should have a direct dependency on libbinder OR one of your \
- dependencies should re-export libbinder headers with export_shared_lib_headers.
diff --git a/include/input/Input.h b/include/input/Input.h
index 5015e68..54c7114 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -803,6 +803,9 @@
static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy);
+ static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&,
+ const PointerCoords&);
+
protected:
int32_t mAction;
int32_t mActionButton;
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index b74923c..ac3e5b8 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -42,12 +42,13 @@
cc_library {
name: "libandroid_runtime_lazy",
vendor_available: true,
+ recovery_available: true,
double_loadable: true,
host_supported: true,
target: {
darwin: {
enabled: false,
- }
+ },
},
cflags: [
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2ecb895..8270ae5 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -25,6 +25,7 @@
name: "libbinder_headers",
export_include_dirs: ["include"],
vendor_available: true,
+ recovery_available: true,
host_supported: true,
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
@@ -75,6 +76,7 @@
vndk: {
enabled: true,
},
+ recovery_available: true,
double_loadable: true,
host_supported: true,
// TODO(b/153609531): remove when no longer needed.
@@ -147,6 +149,11 @@
"UtilsHost.cpp",
],
},
+ recovery: {
+ exclude_header_libs: [
+ "libandroid_runtime_vm_headers",
+ ],
+ },
},
aidl: {
@@ -331,6 +338,7 @@
"libbase",
"libbinder",
"libbinder_ndk",
+ "liblog",
"libutils",
],
export_include_dirs: ["include_rpc_unstable"],
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index d3eef4e..ec9d554 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -547,7 +547,6 @@
AutoMutex _l(e->mLock);
auto rpcServer = RpcServer::make();
LOG_ALWAYS_FATAL_IF(rpcServer == nullptr, "RpcServer::make returns null");
- rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
auto link = sp<RpcServerLink>::make(rpcServer, keepAliveBinder, weakThis);
if (auto status = keepAliveBinder->linkToDeath(link, nullptr, 0); status != OK) {
ALOGE("%s: keepAliveBinder->linkToDeath returns %s", __PRETTY_FUNCTION__,
diff --git a/libs/binder/OWNERS b/libs/binder/OWNERS
index 1c8bdea..f954e74 100644
--- a/libs/binder/OWNERS
+++ b/libs/binder/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 32456
-arve@google.com
ctate@google.com
hackbod@google.com
maco@google.com
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 805e576..745d9e9 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -521,6 +521,25 @@
return memcmp(data(), other.data(), size);
}
+status_t Parcel::compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset,
+ size_t len, int* result) const {
+ if (len > INT32_MAX || thisOffset > INT32_MAX || otherOffset > INT32_MAX) {
+ // Don't accept size_t values which may have come from an inadvertent conversion from a
+ // negative int.
+ return BAD_VALUE;
+ }
+ size_t thisLimit;
+ if (__builtin_add_overflow(thisOffset, len, &thisLimit) || thisLimit > mDataSize) {
+ return BAD_VALUE;
+ }
+ size_t otherLimit;
+ if (__builtin_add_overflow(otherOffset, len, &otherLimit) || otherLimit > other.mDataSize) {
+ return BAD_VALUE;
+ }
+ *result = memcmp(data() + thisOffset, other.data() + otherOffset, len);
+ return NO_ERROR;
+}
+
bool Parcel::allowFds() const
{
return mAllowFds;
@@ -548,21 +567,17 @@
return mHasFds;
}
-status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool& result) const {
+status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool* result) const {
if (len > INT32_MAX || offset > INT32_MAX) {
// Don't accept size_t values which may have come from an inadvertent conversion from a
// negative int.
return BAD_VALUE;
}
- size_t limit = offset + len;
- if (offset > mDataSize || len > mDataSize || limit > mDataSize || offset > limit) {
+ size_t limit;
+ if (__builtin_add_overflow(offset, len, &limit) || limit > mDataSize) {
return BAD_VALUE;
}
- result = hasFileDescriptorsInRangeUnchecked(offset, len);
- return NO_ERROR;
-}
-
-bool Parcel::hasFileDescriptorsInRangeUnchecked(size_t offset, size_t len) const {
+ *result = false;
for (size_t i = 0; i < mObjectsSize; i++) {
size_t pos = mObjects[i];
if (pos < offset) continue;
@@ -572,10 +587,11 @@
}
const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + pos);
if (flat->hdr.type == BINDER_TYPE_FD) {
- return true;
+ *result = true;
+ break;
}
}
- return false;
+ return NO_ERROR;
}
void Parcel::markSensitive() const
@@ -614,6 +630,8 @@
#if defined(__ANDROID_VNDK__)
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
+#elif defined(__ANDROID_RECOVERY__)
+constexpr int32_t kHeader = B_PACK_CHARS('R', 'E', 'C', 'O');
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
#endif
@@ -2184,12 +2202,14 @@
type == BINDER_TYPE_FD)) {
// We should never receive other types (eg BINDER_TYPE_FDA) as long as we don't support
// them in libbinder. If we do receive them, it probably means a kernel bug; try to
- // recover gracefully by clearing out the objects, and releasing the objects we do
- // know about.
+ // recover gracefully by clearing out the objects.
android_errorWriteLog(0x534e4554, "135930648");
+ android_errorWriteLog(0x534e4554, "203847542");
ALOGE("%s: unsupported type object (%" PRIu32 ") at offset %" PRIu64 "\n",
__func__, type, (uint64_t)offset);
- releaseObjects();
+
+ // WARNING: callers of ipcSetDataReference need to make sure they
+ // don't rely on mObjectsSize in their release_func.
mObjectsSize = 0;
break;
}
@@ -2568,9 +2588,9 @@
}
}
-void Parcel::scanForFds() const
-{
- mHasFds = hasFileDescriptorsInRangeUnchecked(0, dataSize());
+void Parcel::scanForFds() const {
+ status_t status = hasFileDescriptorsInRange(0, dataSize(), &mHasFds);
+ ALOGE_IF(status != NO_ERROR, "Error %d calling hasFileDescriptorsInRange()", status);
mFdsKnown = true;
}
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 94b2806..4f21cda 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -89,13 +89,21 @@
return init(nullptr, false /*requireDefault*/);
}
+[[clang::no_destroy]] static sp<ProcessState> gProcess;
+[[clang::no_destroy]] static std::mutex gProcessMutex;
+
+static void verifyNotForked(bool forked) {
+ LOG_ALWAYS_FATAL_IF(forked, "libbinder ProcessState can not be used after fork");
+}
+
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
- [[clang::no_destroy]] static sp<ProcessState> gProcess;
- [[clang::no_destroy]] static std::mutex gProcessMutex;
if (driver == nullptr) {
std::lock_guard<std::mutex> l(gProcessMutex);
+ if (gProcess) {
+ verifyNotForked(gProcess->mForked);
+ }
return gProcess;
}
@@ -106,6 +114,14 @@
driver = "/dev/binder";
}
+ // we must install these before instantiating the gProcess object,
+ // otherwise this would race with creating it, and there could be the
+ // possibility of an invalid gProcess object forked by another thread
+ // before these are installed
+ int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
+ ProcessState::childPostFork);
+ LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));
+
std::lock_guard<std::mutex> l(gProcessMutex);
gProcess = sp<ProcessState>::make(driver);
});
@@ -119,6 +135,7 @@
gProcess->getDriverName().c_str(), driver);
}
+ verifyNotForked(gProcess->mForked);
return gProcess;
}
@@ -137,6 +154,24 @@
return context;
}
+void ProcessState::onFork() {
+ // make sure another thread isn't currently retrieving ProcessState
+ gProcessMutex.lock();
+}
+
+void ProcessState::parentPostFork() {
+ gProcessMutex.unlock();
+}
+
+void ProcessState::childPostFork() {
+ // another thread might call fork before gProcess is instantiated, but after
+ // the thread handler is installed
+ if (gProcess) {
+ gProcess->mForked = true;
+ }
+ gProcessMutex.unlock();
+}
+
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
@@ -426,6 +461,7 @@
mWaitingForThreads(0),
mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
mStarvationStartTimeMs(0),
+ mForked(false),
mThreadPoolStarted(false),
mThreadPoolSeq(1),
mCallRestriction(CallRestriction::NONE) {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 967b8e3..93ed50e 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -58,10 +58,6 @@
return sp<RpcServer>::make(std::move(ctx));
}
-void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
- mAgreedExperimental = true;
-}
-
status_t RpcServer::setupUnixDomainServer(const char* path) {
return setupSocketServer(UnixSocketAddress(path));
}
@@ -127,14 +123,23 @@
void RpcServer::setRootObject(const sp<IBinder>& binder) {
std::lock_guard<std::mutex> _l(mLock);
+ mRootObjectFactory = nullptr;
mRootObjectWeak = mRootObject = binder;
}
void RpcServer::setRootObjectWeak(const wp<IBinder>& binder) {
std::lock_guard<std::mutex> _l(mLock);
mRootObject.clear();
+ mRootObjectFactory = nullptr;
mRootObjectWeak = binder;
}
+void RpcServer::setPerSessionRootObject(
+ std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& makeObject) {
+ std::lock_guard<std::mutex> _l(mLock);
+ mRootObject.clear();
+ mRootObjectWeak.clear();
+ mRootObjectFactory = std::move(makeObject);
+}
sp<IBinder> RpcServer::getRootObject() {
std::lock_guard<std::mutex> _l(mLock);
@@ -154,14 +159,12 @@
}
void RpcServer::start() {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
std::lock_guard<std::mutex> _l(mLock);
LOG_ALWAYS_FATAL_IF(mJoinThread.get(), "Already started!");
mJoinThread = std::make_unique<std::thread>(&joinRpcServer, sp<RpcServer>::fromExisting(this));
}
void RpcServer::join() {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
{
std::lock_guard<std::mutex> _l(mLock);
@@ -174,8 +177,14 @@
status_t status;
while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
- unique_fd clientFd(TEMP_FAILURE_RETRY(
- accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC | SOCK_NONBLOCK)));
+ sockaddr_storage addr;
+ socklen_t addrLen = sizeof(addr);
+
+ unique_fd clientFd(
+ TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(&addr),
+ &addrLen, SOCK_CLOEXEC | SOCK_NONBLOCK)));
+
+ LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(addr)), "Truncated address");
if (clientFd < 0) {
ALOGE("Could not accept4 socket: %s", strerror(errno));
@@ -187,7 +196,7 @@
std::lock_guard<std::mutex> _l(mLock);
std::thread thread =
std::thread(&RpcServer::establishConnection, sp<RpcServer>::fromExisting(this),
- std::move(clientFd));
+ std::move(clientFd), addr, addrLen);
mConnectingThreads[thread.get_id()] = std::move(thread);
}
}
@@ -257,10 +266,8 @@
return mConnectingThreads.size();
}
-void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd) {
- // TODO(b/183988761): cannot trust this simple ID
- LOG_ALWAYS_FATAL_IF(!server->mAgreedExperimental, "no!");
-
+void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
+ const sockaddr_storage addr, socklen_t addrLen) {
// mShutdownTrigger can only be cleared once connection threads have joined.
// It must be set before this thread is started
LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
@@ -383,11 +390,23 @@
session = RpcSession::make();
session->setMaxIncomingThreads(server->mMaxThreads);
if (!session->setProtocolVersion(protocolVersion)) return;
+
+ // if null, falls back to server root
+ sp<IBinder> sessionSpecificRoot;
+ if (server->mRootObjectFactory != nullptr) {
+ sessionSpecificRoot =
+ server->mRootObjectFactory(reinterpret_cast<const sockaddr*>(&addr),
+ addrLen);
+ if (sessionSpecificRoot == nullptr) {
+ ALOGE("Warning: server returned null from root object factory");
+ }
+ }
+
if (!session->setForServer(server,
sp<RpcServer::EventListener>::fromExisting(
static_cast<RpcServer::EventListener*>(
server.get())),
- sessionId)) {
+ sessionId, sessionSpecificRoot)) {
ALOGE("Failed to attach server to session");
return;
}
@@ -478,19 +497,16 @@
}
bool RpcServer::hasServer() {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
std::lock_guard<std::mutex> _l(mLock);
return mServer.ok();
}
unique_fd RpcServer::releaseServer() {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
std::lock_guard<std::mutex> _l(mLock);
return std::move(mServer);
}
status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
std::lock_guard<std::mutex> _l(mLock);
if (mServer.ok()) {
ALOGE("Each RpcServer can only have one server.");
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 9eef3e8..a5a2bb1 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -29,13 +29,11 @@
#include <android-base/hex.h>
#include <android-base/macros.h>
#include <android-base/scopeguard.h>
-#include <android_runtime/vm.h>
#include <binder/BpBinder.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
#include <binder/RpcTransportRaw.h>
#include <binder/Stability.h>
-#include <jni.h>
#include <utils/String8.h>
#include "FdTrigger.h"
@@ -48,6 +46,11 @@
extern "C" pid_t gettid();
#endif
+#ifndef __ANDROID_RECOVERY__
+#include <android_runtime/vm.h>
+#include <jni.h>
+#endif
+
namespace android {
using base::unique_fd;
@@ -315,6 +318,9 @@
}
namespace {
+#ifdef __ANDROID_RECOVERY__
+class JavaThreadAttacher {};
+#else
// RAII object for attaching / detaching current thread to JVM if Android Runtime exists. If
// Android Runtime doesn't exist, no-op.
class JavaThreadAttacher {
@@ -367,6 +373,7 @@
return fn();
}
};
+#endif
} // namespace
void RpcSession::join(sp<RpcSession>&& session, PreJoinSetupResult&& setupResult) {
@@ -374,7 +381,7 @@
if (setupResult.status == OK) {
LOG_ALWAYS_FATAL_IF(!connection, "must have connection if setup succeeded");
- JavaThreadAttacher javaThreadAttacher;
+ [[maybe_unused]] JavaThreadAttacher javaThreadAttacher;
while (true) {
status_t status = session->state()->getAndExecuteCommand(connection, session,
RpcState::CommandType::ANY);
@@ -688,7 +695,8 @@
status_t status = OK;
if (init) {
- mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+ status =
+ mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
}
{
@@ -700,7 +708,8 @@
}
bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
- const std::vector<uint8_t>& sessionId) {
+ const std::vector<uint8_t>& sessionId,
+ const sp<IBinder>& sessionSpecificRoot) {
LOG_ALWAYS_FATAL_IF(mForServer != nullptr);
LOG_ALWAYS_FATAL_IF(server == nullptr);
LOG_ALWAYS_FATAL_IF(mEventListener != nullptr);
@@ -713,6 +722,7 @@
mId = sessionId;
mForServer = server;
mEventListener = eventListener;
+ mSessionSpecificRootObject = sessionSpecificRoot;
return true;
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 9ba64f3..09b3d68 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -870,7 +870,9 @@
if (server) {
switch (transaction->code) {
case RPC_SPECIAL_TRANSACT_GET_ROOT: {
- replyStatus = reply.writeStrongBinder(server->getRootObject());
+ sp<IBinder> root = session->mSessionSpecificRootObject
+ ?: server->getRootObject();
+ replyStatus = reply.writeStrongBinder(root);
break;
}
default: {
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 50de22b..dba0a43 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -60,20 +60,21 @@
RpcState();
~RpcState();
- status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, uint32_t* version);
- status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session);
- status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session);
+ [[nodiscard]] status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint32_t* version);
+ [[nodiscard]] status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session);
+ [[nodiscard]] status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session);
// TODO(b/182940634): combine some special transactions into one "getServerInfo" call?
sp<IBinder> getRootObject(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session);
- status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, size_t* maxThreadsOut);
- status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, std::vector<uint8_t>* sessionIdOut);
+ [[nodiscard]] status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, size_t* maxThreadsOut);
+ [[nodiscard]] status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session,
+ std::vector<uint8_t>* sessionIdOut);
[[nodiscard]] status_t transact(const sp<RpcSession::RpcConnection>& connection,
const sp<IBinder>& address, uint32_t code, const Parcel& data,
diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
index ece7989..bffab5e 100644
--- a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
+++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
@@ -27,4 +27,7 @@
@utf8InCpp String diskImagePath;
long versionCode;
@utf8InCpp String versionName;
+ boolean hasBootClassPathJars;
+ boolean hasDex2OatBootClassPathJars;
+ boolean hasSystemServerClassPathJars;
}
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index ff90b30..7d14315 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -129,48 +129,50 @@
#endif
-#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)\
- const ::android::StaticString16 \
- I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\
- const ::android::String16 I##INTERFACE::descriptor( \
- I##INTERFACE##_descriptor_static_str16); \
- const ::android::String16& \
- I##INTERFACE::getInterfaceDescriptor() const { \
- return I##INTERFACE::descriptor; \
- } \
- ::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
- const ::android::sp<::android::IBinder>& obj) \
- { \
- ::android::sp<I##INTERFACE> intr; \
- if (obj != nullptr) { \
- intr = ::android::sp<I##INTERFACE>::cast( \
- obj->queryLocalInterface(I##INTERFACE::descriptor)); \
- if (intr == nullptr) { \
- intr = ::android::sp<Bp##INTERFACE>::make(obj); \
- } \
- } \
- return intr; \
- } \
- std::unique_ptr<I##INTERFACE> I##INTERFACE::default_impl; \
- bool I##INTERFACE::setDefaultImpl(std::unique_ptr<I##INTERFACE> impl)\
- { \
- /* Only one user of this interface can use this function */ \
- /* at a time. This is a heuristic to detect if two different */ \
- /* users in the same process use this function. */ \
- assert(!I##INTERFACE::default_impl); \
- if (impl) { \
- I##INTERFACE::default_impl = std::move(impl); \
- return true; \
- } \
- return false; \
- } \
- const std::unique_ptr<I##INTERFACE>& I##INTERFACE::getDefaultImpl() \
- { \
- return I##INTERFACE::default_impl; \
- } \
- I##INTERFACE::I##INTERFACE() { } \
- I##INTERFACE::~I##INTERFACE() { } \
+// Macro to be used by both IMPLEMENT_META_INTERFACE and IMPLEMENT_META_NESTED_INTERFACE
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(ITYPE, INAME, BPTYPE) \
+ const ::android::String16& ITYPE::getInterfaceDescriptor() const { return ITYPE::descriptor; } \
+ ::android::sp<ITYPE> ITYPE::asInterface(const ::android::sp<::android::IBinder>& obj) { \
+ ::android::sp<ITYPE> intr; \
+ if (obj != nullptr) { \
+ intr = ::android::sp<ITYPE>::cast(obj->queryLocalInterface(ITYPE::descriptor)); \
+ if (intr == nullptr) { \
+ intr = ::android::sp<BPTYPE>::make(obj); \
+ } \
+ } \
+ return intr; \
+ } \
+ std::unique_ptr<ITYPE> ITYPE::default_impl; \
+ bool ITYPE::setDefaultImpl(std::unique_ptr<ITYPE> impl) { \
+ /* Only one user of this interface can use this function */ \
+ /* at a time. This is a heuristic to detect if two different */ \
+ /* users in the same process use this function. */ \
+ assert(!ITYPE::default_impl); \
+ if (impl) { \
+ ITYPE::default_impl = std::move(impl); \
+ return true; \
+ } \
+ return false; \
+ } \
+ const std::unique_ptr<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \
+ ITYPE::INAME() {} \
+ ITYPE::~INAME() {}
+// Macro for an interface type.
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
+ const ::android::StaticString16 I##INTERFACE##_descriptor_static_str16( \
+ __IINTF_CONCAT(u, NAME)); \
+ const ::android::String16 I##INTERFACE::descriptor(I##INTERFACE##_descriptor_static_str16); \
+ DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(I##INTERFACE, I##INTERFACE, Bp##INTERFACE)
+
+// Macro for "nested" interface type.
+// For example,
+// class Parent .. { class INested .. { }; };
+// DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE(Parent, Nested, "Parent.INested")
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE(PARENT, INTERFACE, NAME) \
+ const ::android::String16 PARENT::I##INTERFACE::descriptor(NAME); \
+ DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(PARENT::I##INTERFACE, I##INTERFACE, \
+ PARENT::Bp##INTERFACE)
#define CHECK_INTERFACE(interface, data, reply) \
do { \
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index cf30f17..9670d7b 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -81,13 +81,15 @@
size_t start, size_t len);
int compareData(const Parcel& other);
+ status_t compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset,
+ size_t length, int* result) const;
bool allowFds() const;
bool pushAllowFds(bool allowFds);
void restoreAllowFds(bool lastValue);
bool hasFileDescriptors() const;
- status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool& result) const;
+ status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool* result) const;
// Zeros data when reallocating. Other mitigations may be added
// in the future.
@@ -205,6 +207,23 @@
status_t writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
+ // Write an IInterface or a vector of IInterface's
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinder(const sp<T>& val) {
+ return writeStrongBinder(T::asBinder(val));
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinderVector(const std::vector<sp<T>>& val) {
+ return writeData(val);
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinderVector(const std::optional<std::vector<sp<T>>>& val) {
+ return writeData(val);
+ }
+
// Write an Enum vector with underlying type int8_t.
// Does not use padding; each byte is contiguous.
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
@@ -419,6 +438,16 @@
status_t readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const;
status_t readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t readStrongBinderVector(std::vector<sp<T>>* val) const {
+ return readData(val);
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t readStrongBinderVector(std::optional<std::vector<sp<T>>>* val) const {
+ return readData(val);
+ }
status_t readByteVector(std::optional<std::vector<int8_t>>* val) const;
status_t readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
@@ -576,7 +605,6 @@
status_t writeRawNullableParcelable(const Parcelable*
parcelable);
- bool hasFileDescriptorsInRangeUnchecked(size_t offset, size_t length) const;
//-----------------------------------------------------------------------------
// Generic type read and write methods for Parcel:
@@ -1237,7 +1265,9 @@
*/
size_t getOpenAshmemSize() const;
- // TODO(b/202029388): Remove 'getBlobAshmemSize' once ABI can be changed.
+private:
+ // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference
+ // this
size_t getBlobAshmemSize() const;
};
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 72c2ab7..cf8d8e4 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -94,6 +94,10 @@
private:
static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);
+ static void onFork();
+ static void parentPostFork();
+ static void childPostFork();
+
friend class IPCThreadState;
friend class sp<ProcessState>;
@@ -132,6 +136,7 @@
Vector<handle_entry> mHandleToObject;
+ bool mForked;
bool mThreadPoolStarted;
volatile int32_t mThreadPoolSeq;
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index fb2cf23..aaa812b 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -25,10 +25,6 @@
#include <mutex>
#include <thread>
-// WARNING: This is a feature which is still in development, and it is subject
-// to radical change. Any production use of this may subject your code to any
-// number of problems.
-
namespace android {
class FdTrigger;
@@ -99,8 +95,6 @@
*/
[[nodiscard]] status_t setupExternalServer(base::unique_fd serverFd);
- void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-
/**
* This must be called before adding a client session.
*
@@ -130,6 +124,10 @@
* Holds a weak reference to the root object.
*/
void setRootObjectWeak(const wp<IBinder>& binder);
+ /**
+ * Allows a root object to be created for each session
+ */
+ void setPerSessionRootObject(std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& object);
sp<IBinder> getRootObject();
/**
@@ -179,11 +177,11 @@
void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
- static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd);
- status_t setupSocketServer(const RpcSocketAddress& address);
+ static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
+ const sockaddr_storage addr, socklen_t addrLen);
+ [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
const std::unique_ptr<RpcTransportCtx> mCtx;
- bool mAgreedExperimental = false;
size_t mMaxThreads = 1;
std::optional<uint32_t> mProtocolVersion;
base::unique_fd mServer; // socket we are accepting sessions on
@@ -194,6 +192,7 @@
std::map<std::thread::id, std::thread> mConnectingThreads;
sp<IBinder> mRootObject;
wp<IBinder> mRootObjectWeak;
+ std::function<sp<IBinder>(const sockaddr*, socklen_t)> mRootObjectFactory;
std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
std::unique_ptr<FdTrigger> mShutdownTrigger;
std::condition_variable mShutdownCv;
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index f5505da..1bc8464 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -26,10 +26,6 @@
#include <thread>
#include <vector>
-// WARNING: This is a feature which is still in development, and it is subject
-// to radical change. Any production use of this may subject your code to any
-// number of problems.
-
namespace android {
class Parcel;
@@ -140,7 +136,7 @@
* Query the other side of the session for the maximum number of threads
* it supports (maximum number of concurrent non-nested synchronous transactions)
*/
- status_t getRemoteMaxThreads(size_t* maxThreads);
+ [[nodiscard]] status_t getRemoteMaxThreads(size_t* maxThreads);
/**
* See RpcTransportCtx::getCertificate
@@ -220,7 +216,7 @@
bool allowNested = false;
};
- status_t readId();
+ [[nodiscard]] status_t readId();
// A thread joining a server must always call these functions in order, and
// cleanup is only programmed once into join. These are in separate
@@ -256,12 +252,13 @@
bool init);
[[nodiscard]] bool setForServer(const wp<RpcServer>& server,
const wp<RpcSession::EventListener>& eventListener,
- const std::vector<uint8_t>& sessionId);
+ const std::vector<uint8_t>& sessionId,
+ const sp<IBinder>& sessionSpecificRoot);
sp<RpcConnection> assignIncomingConnectionToThisThread(
std::unique_ptr<RpcTransport> rpcTransport);
[[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
- status_t initShutdownTrigger();
+ [[nodiscard]] status_t initShutdownTrigger();
enum class ConnectionUse {
CLIENT,
@@ -272,8 +269,8 @@
// Object representing exclusive access to a connection.
class ExclusiveConnection {
public:
- static status_t find(const sp<RpcSession>& session, ConnectionUse use,
- ExclusiveConnection* connection);
+ [[nodiscard]] static status_t find(const sp<RpcSession>& session, ConnectionUse use,
+ ExclusiveConnection* connection);
~ExclusiveConnection();
const sp<RpcConnection>& get() { return mConnection; }
@@ -313,6 +310,10 @@
sp<WaitForShutdownListener> mShutdownListener; // used for client sessions
wp<EventListener> mEventListener; // mForServer if server, mShutdownListener if client
+ // session-specific root object (if a different root is used for each
+ // session)
+ sp<IBinder> mSessionSpecificRootObject;
+
std::vector<uint8_t> mId;
std::unique_ptr<FdTrigger> mShutdownTrigger;
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 08f5eed..34f1cbf 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -16,6 +16,8 @@
#pragma once
+#include <sys/socket.h>
+
extern "C" {
struct AIBinder;
@@ -30,6 +32,12 @@
bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
void* param);
+// Starts an RPC server on a given port and a given root IBinder object.
+// This function sets up the server, calls readyCallback with a given param, and
+// then joins before returning.
+bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
+ void* factoryContext, unsigned int port);
+
AIBinder* RpcClient(unsigned int cid, unsigned int port);
// Connect to an RPC server with preconnected file descriptors.
diff --git a/libs/binder/include_tls/binder/RpcAuth.h b/libs/binder/include_tls/binder/RpcAuth.h
index 4c2f296..ab64828 100644
--- a/libs/binder/include_tls/binder/RpcAuth.h
+++ b/libs/binder/include_tls/binder/RpcAuth.h
@@ -40,7 +40,7 @@
// - SSL_CTX_use_certificate
// - SSL_CTX_set*_chain
// - SSL_CTX_add0_chain_cert
- virtual status_t configure(SSL_CTX* ctx) = 0;
+ [[nodiscard]] virtual status_t configure(SSL_CTX* ctx) = 0;
};
} // namespace android
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index cad55fb..bf2b25b 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -19,6 +19,7 @@
#include <android/binder_libbinder.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <linux/vm_sockets.h>
using android::OK;
using android::RpcServer;
@@ -29,10 +30,31 @@
extern "C" {
+bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
+ void* factoryContext, unsigned int port) {
+ auto server = RpcServer::make();
+ if (status_t status = server->setupVsockServer(port); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock server with port " << port
+ << " error: " << statusToString(status).c_str();
+ return false;
+ }
+ server->setPerSessionRootObject([=](const sockaddr* addr, socklen_t addrlen) {
+ LOG_ALWAYS_FATAL_IF(addr->sa_family != AF_VSOCK, "address is not a vsock");
+ LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
+ const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
+ return AIBinder_toPlatformBinder(factory(vaddr->svm_cid, factoryContext));
+ });
+
+ server->join();
+
+ // Shutdown any open sessions since server failed.
+ (void)server->shutdown();
+ return true;
+}
+
bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
void* param) {
auto server = RpcServer::make();
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
if (status_t status = server->setupVsockServer(port); status != OK) {
LOG(ERROR) << "Failed to set up vsock server with port " << port
<< " error: " << statusToString(status).c_str();
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 9c04e58..ee46fcb 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -54,6 +54,7 @@
defaults: ["libbinder_ndk_host_user"],
host_supported: true,
+ recovery_available: true,
llndk: {
symbol_file: "libbinder_ndk.map.txt",
@@ -155,6 +156,7 @@
name: "libbinder_headers_platform_shared",
export_include_dirs: ["include_cpp"],
vendor_available: true,
+ recovery_available: true,
host_supported: true,
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 49c7b7c..6949c2c 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -104,6 +104,17 @@
return {};
}
+// b/175635923 libcxx causes "implicit-conversion" with a string with invalid char
+static std::string SanitizeString(const String16& str) {
+ std::string sanitized{String8(str)};
+ for (auto& c : sanitized) {
+ if (!isprint(c)) {
+ c = '?';
+ }
+ }
+ return sanitized;
+}
+
bool AIBinder::associateClass(const AIBinder_Class* clazz) {
if (clazz == nullptr) return false;
@@ -118,7 +129,7 @@
if (descriptor != newDescriptor) {
if (getBinder()->isBinderAlive()) {
LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor
- << "' but descriptor is actually '" << descriptor << "'.";
+ << "' but descriptor is actually '" << SanitizeString(descriptor) << "'.";
} else {
// b/155793159
LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
@@ -555,6 +566,10 @@
return ::android::IPCThreadState::self()->getCallingPid();
}
+bool AIBinder_isHandlingTransaction() {
+ return ::android::IPCThreadState::self()->getServingStackPointer() != nullptr;
+}
+
void AIBinder_incStrong(AIBinder* binder) {
if (binder == nullptr) {
return;
@@ -780,3 +795,7 @@
AIBinder_incStrong(ndkBinder.get());
return ndkBinder.get();
}
+
+void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) {
+ binder->asABBinder()->setMinSchedulerPolicy(policy, priority);
+}
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 4a7b664..67623a6 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -27,15 +27,67 @@
#pragma once
#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
#include <android/binder_internal_logging.h>
#include <android/binder_parcel.h>
#include <optional>
#include <string>
+#include <type_traits>
#include <vector>
namespace ndk {
+namespace {
+template <typename Test, template <typename...> class Ref>
+struct is_specialization : std::false_type {};
+
+template <template <typename...> class Ref, typename... Args>
+struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
+
+template <typename Test, template <typename...> class Ref>
+static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
+
+// Get the first template type from a container, the T from MyClass<T, ...>.
+template <typename T>
+struct first_template_type {
+ using type = void;
+};
+
+template <template <typename...> class V, typename T, typename... Args>
+struct first_template_type<V<T, Args...>> {
+ using type = T;
+};
+
+template <typename T>
+using first_template_type_t = typename first_template_type<T>::type;
+
+// Tells if T represents NDK interface (shared_ptr<ICInterface-derived>)
+template <typename T>
+static inline constexpr bool is_interface_v = is_specialization_v<T, std::shared_ptr>&&
+ std::is_base_of_v<::ndk::ICInterface, first_template_type_t<T>>;
+
+// Tells if T represents NDK parcelable with readFromParcel/writeToParcel methods defined
+template <typename T, typename = void>
+struct is_parcelable : std::false_type {};
+
+template <typename T>
+struct is_parcelable<
+ T, std::void_t<decltype(std::declval<T>().readFromParcel(std::declval<const AParcel*>())),
+ decltype(std::declval<T>().writeToParcel(std::declval<AParcel*>()))>>
+ : std::true_type {};
+
+template <typename T>
+static inline constexpr bool is_parcelable_v = is_parcelable<T>::value;
+
+// Tells if T represents nullable NDK parcelable (optional<parcelable> or unique_ptr<parcelable>)
+template <typename T>
+static inline constexpr bool is_nullable_parcelable_v = is_parcelable_v<first_template_type_t<T>> &&
+ (is_specialization_v<T, std::optional> ||
+ is_specialization_v<T, std::unique_ptr>);
+
+} // namespace
+
/**
* This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
*/
@@ -429,11 +481,19 @@
*/
template <typename P>
static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) {
- binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
- if (status != STATUS_OK) {
- return status;
+ if constexpr (is_interface_v<P>) {
+ if (!p) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ return first_template_type_t<P>::writeToParcel(parcel, p);
+ } else {
+ static_assert(is_parcelable_v<P>);
+ binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return p.writeToParcel(parcel);
}
- return p.writeToParcel(parcel);
}
/**
@@ -441,85 +501,81 @@
*/
template <typename P>
static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) {
- int32_t null;
- binder_status_t status = AParcel_readInt32(parcel, &null);
- if (status != STATUS_OK) {
+ if constexpr (is_interface_v<P>) {
+ binder_status_t status = first_template_type_t<P>::readFromParcel(parcel, p);
+ if (status == STATUS_OK) {
+ if (!*p) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ }
return status;
+ } else {
+ static_assert(is_parcelable_v<P>);
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ return p->readFromParcel(parcel);
}
- if (null == 0) {
- return STATUS_UNEXPECTED_NULL;
- }
- return p->readFromParcel(parcel);
}
/**
* Convenience API for writing a nullable parcelable.
*/
template <typename P>
-static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
- const std::optional<P>& p) {
- if (p == std::nullopt) {
- return AParcel_writeInt32(parcel, 0); // null
+static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel, const P& p) {
+ if constexpr (is_interface_v<P>) {
+ return first_template_type_t<P>::writeToParcel(parcel, p);
+ } else {
+ static_assert(is_nullable_parcelable_v<P>);
+ if (!p) {
+ return AParcel_writeInt32(parcel, 0); // null
+ }
+ binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return p->writeToParcel(parcel);
}
- binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
- if (status != STATUS_OK) {
- return status;
- }
- return p->writeToParcel(parcel);
-}
-
-/**
- * Convenience API for writing a nullable parcelable.
- */
-template <typename P>
-static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
- const std::unique_ptr<P>& p) {
- if (!p) {
- return AParcel_writeInt32(parcel, 0); // null
- }
- binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
- if (status != STATUS_OK) {
- return status;
- }
- return p->writeToParcel(parcel);
}
/**
* Convenience API for reading a nullable parcelable.
*/
template <typename P>
-static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
- std::optional<P>* p) {
- int32_t null;
- binder_status_t status = AParcel_readInt32(parcel, &null);
- if (status != STATUS_OK) {
- return status;
+static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel, P* p) {
+ if constexpr (is_interface_v<P>) {
+ return first_template_type_t<P>::readFromParcel(parcel, p);
+ } else if constexpr (is_specialization_v<P, std::optional>) {
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ *p = std::nullopt;
+ return STATUS_OK;
+ }
+ *p = std::optional<first_template_type_t<P>>(first_template_type_t<P>{});
+ return (*p)->readFromParcel(parcel);
+ } else {
+ static_assert(is_specialization_v<P, std::unique_ptr>);
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ p->reset();
+ return STATUS_OK;
+ }
+ *p = std::make_unique<first_template_type_t<P>>();
+ return (*p)->readFromParcel(parcel);
}
- if (null == 0) {
- *p = std::nullopt;
- return STATUS_OK;
- }
- *p = std::optional<P>(P{});
- return (*p)->readFromParcel(parcel);
-}
-
-/**
- * Convenience API for reading a nullable parcelable.
- */
-template <typename P>
-static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
- std::unique_ptr<P>* p) {
- int32_t null;
- binder_status_t status = AParcel_readInt32(parcel, &null);
- if (status != STATUS_OK) {
- return status;
- }
- if (null == 0) {
- p->reset();
- return STATUS_OK;
- }
- *p = std::make_unique<P>();
- return (*p)->readFromParcel(parcel);
}
/**
@@ -550,8 +606,8 @@
const void* vectorData,
size_t index) {
const std::optional<std::vector<P>>* vector =
- static_cast<const std::optional<std::vector<P>*>>(vectorData);
- return AParcel_writeNullableParcelable(parcel, vector->at(index));
+ static_cast<const std::optional<std::vector<P>>*>(vectorData);
+ return AParcel_writeNullableParcelable(parcel, (*vector)->at(index));
}
/**
@@ -561,7 +617,7 @@
binder_status_t AParcel_readNullableStdVectorParcelableElement(const AParcel* parcel,
void* vectorData, size_t index) {
std::optional<std::vector<P>>* vector = static_cast<std::optional<std::vector<P>>*>(vectorData);
- return AParcel_readNullableParcelable(parcel, &vector->at(index));
+ return AParcel_readNullableParcelable(parcel, &(*vector)->at(index));
}
/**
@@ -573,11 +629,7 @@
AParcel* parcel, const void* vectorData, size_t index) {
const std::vector<ScopedFileDescriptor>* vector =
static_cast<const std::vector<ScopedFileDescriptor>*>(vectorData);
- int writeFd = vector->at(index).get();
- if (writeFd < 0) {
- return STATUS_UNEXPECTED_NULL;
- }
- return AParcel_writeParcelFileDescriptor(parcel, writeFd);
+ return AParcel_writeRequiredParcelFileDescriptor(parcel, vector->at(index));
}
/**
@@ -589,15 +641,31 @@
const AParcel* parcel, void* vectorData, size_t index) {
std::vector<ScopedFileDescriptor>* vector =
static_cast<std::vector<ScopedFileDescriptor>*>(vectorData);
- int readFd;
- binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
- if (status == STATUS_OK) {
- if (readFd < 0) {
- return STATUS_UNEXPECTED_NULL;
- }
- vector->at(index).set(readFd);
- }
- return status;
+ return AParcel_readRequiredParcelFileDescriptor(parcel, &vector->at(index));
+}
+
+/**
+ * Writes a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
+ * index 'index' to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<ScopedFileDescriptor>(
+ AParcel* parcel, const void* vectorData, size_t index) {
+ const std::optional<std::vector<ScopedFileDescriptor>>* vector =
+ static_cast<const std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
+ return AParcel_writeNullableParcelFileDescriptor(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
+ * index 'index' from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readNullableStdVectorParcelableElement<ScopedFileDescriptor>(
+ const AParcel* parcel, void* vectorData, size_t index) {
+ std::optional<std::vector<ScopedFileDescriptor>>* vector =
+ static_cast<std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
+ return AParcel_readNullableParcelFileDescriptor(parcel, &(*vector)->at(index));
}
/**
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 782328d..4163897 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -393,6 +393,14 @@
pid_t AIBinder_getCallingPid() __INTRODUCED_IN(29);
/**
+ * Determine whether the current thread is currently executing an incoming transaction.
+ *
+ * \return true if the current thread is currently executing an incoming transaction, and false
+ * otherwise.
+ */
+bool AIBinder_isHandlingTransaction() __INTRODUCED_IN(33);
+
+/**
* This can only be called if a strong reference to this object already exists in process.
*
* Available since API level 29.
diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
index e315c79..b0217c4 100644
--- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -55,4 +55,17 @@
*/
__attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
+/**
+ * Sets a minimum scheduler policy for all transactions coming into this
+ * AIBinder.
+ *
+ * This must be called before the object is sent to another process.
+ * Aborts on invalid values. Not thread safe.
+ *
+ * \param binder local server binder to set the policy for
+ * \param policy scheduler policy as defined in linux UAPI
+ * \param priority priority. [-20..19] for SCHED_NORMAL, [1..99] for RT
+ */
+void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) __INTRODUCED_IN(33);
+
__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 8605686..d63a8d0 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -145,6 +145,8 @@
global:
AIBinder_Class_disableInterfaceTokenHeader;
AIBinder_DeathRecipient_setOnUnlinked;
+ AIBinder_isHandlingTransaction;
+ AIBinder_setMinSchedulerPolicy; # llndk
AParcel_marshal;
AParcel_unmarshal;
};
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index ecb044e..d323022 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -33,6 +33,27 @@
}
rust_library {
+ name: "libbinder_tokio_rs",
+ crate_name: "binder_tokio",
+ srcs: ["binder_tokio/lib.rs"],
+ rustlibs: [
+ "libbinder_rs",
+ "libtokio",
+ ],
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
+ "com.android.virt",
+ ],
+}
+
+rust_library {
name: "libbinder_ndk_sys",
crate_name: "binder_ndk_sys",
srcs: [
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
new file mode 100644
index 0000000..64833b6
--- /dev/null
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! This crate lets you use the Tokio `spawn_blocking` pool with AIDL in async
+//! Rust code.
+//!
+//! This crate works by defining a type [`Tokio`], which you can use as the
+//! generic parameter in the async version of the trait generated by the AIDL
+//! compiler.
+//! ```text
+//! use binder_tokio::Tokio;
+//!
+//! binder::get_interface::<dyn SomeAsyncInterface<Tokio>>("...").
+//! ```
+//!
+//! [`Tokio`]: crate::Tokio
+
+use binder::public_api::{BinderAsyncPool, BoxFuture, Strong};
+use binder::{FromIBinder, StatusCode};
+use std::future::Future;
+
+/// Retrieve an existing service for a particular interface, sleeping for a few
+/// seconds if it doesn't yet exist.
+pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+ let name = name.to_string();
+ let res = tokio::task::spawn_blocking(move || {
+ binder::public_api::get_interface::<T>(&name)
+ }).await;
+
+ // The `is_panic` branch is not actually reachable in Android as we compile
+ // with `panic = abort`.
+ match res {
+ Ok(Ok(service)) => Ok(service),
+ Ok(Err(err)) => Err(err),
+ Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+ Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+ Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+ }
+}
+
+/// Retrieve an existing service for a particular interface, or start it if it
+/// is configured as a dynamic service and isn't yet started.
+pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+ let name = name.to_string();
+ let res = tokio::task::spawn_blocking(move || {
+ binder::public_api::wait_for_interface::<T>(&name)
+ }).await;
+
+ // The `is_panic` branch is not actually reachable in Android as we compile
+ // with `panic = abort`.
+ match res {
+ Ok(Ok(service)) => Ok(service),
+ Ok(Err(err)) => Err(err),
+ Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+ Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+ Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+ }
+}
+
+/// Use the Tokio `spawn_blocking` pool with AIDL.
+pub enum Tokio {}
+
+impl BinderAsyncPool for Tokio {
+ fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+ where
+ F1: FnOnce() -> A,
+ F2: FnOnce(A) -> Fut,
+ Fut: Future<Output = Result<B, E>>,
+ F1: Send + 'static,
+ F2: Send + 'a,
+ Fut: Send + 'a,
+ A: Send + 'static,
+ B: Send + 'a,
+ E: From<crate::StatusCode>,
+ {
+ let handle = tokio::task::spawn_blocking(spawn_me);
+ Box::pin(async move {
+ // The `is_panic` branch is not actually reachable in Android as we compile
+ // with `panic = abort`.
+ match handle.await {
+ Ok(res) => after_spawn(res).await,
+ Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+ Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION.into()),
+ Err(_) => Err(StatusCode::UNKNOWN_ERROR.into()),
+ }
+ })
+ }
+}
+
+
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 854b1f9..4e048d7 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,7 +17,7 @@
//! Trait definitions for binder objects
use crate::error::{status_t, Result, StatusCode};
-use crate::parcel::Parcel;
+use crate::parcel::{OwnedParcel, Parcel};
use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;
@@ -177,25 +177,25 @@
fn get_extension(&mut self) -> Result<Option<SpIBinder>>;
/// Create a Parcel that can be used with `submit_transact`.
- fn prepare_transact(&self) -> Result<Parcel>;
+ fn prepare_transact(&self) -> Result<OwnedParcel>;
/// Perform a generic operation with the object.
///
- /// The provided [`Parcel`] must have been created by a call to
+ /// The provided [`OwnedParcel`] must have been created by a call to
/// `prepare_transact` on the same binder.
///
/// # Arguments
///
/// * `code` - Transaction code for the operation.
- /// * `data` - [`Parcel`] with input data.
+ /// * `data` - [`OwnedParcel`] with input data.
/// * `flags` - Transaction flags, e.g. marking the transaction as
/// asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY)).
fn submit_transact(
&self,
code: TransactionCode,
- data: Parcel,
+ data: OwnedParcel,
flags: TransactionFlags,
- ) -> Result<Parcel>;
+ ) -> Result<OwnedParcel>;
/// Perform a generic operation with the object. This is a convenience
/// method that internally calls `prepare_transact` followed by
@@ -213,8 +213,8 @@
input_callback: F,
) -> Result<Parcel> {
let mut parcel = self.prepare_transact()?;
- input_callback(&mut parcel)?;
- self.submit_transact(code, parcel, flags)
+ input_callback(&mut parcel.borrowed())?;
+ self.submit_transact(code, parcel, flags).map(OwnedParcel::into_parcel)
}
}
@@ -713,12 +713,14 @@
$interface:path[$descriptor:expr] {
native: $native:ident($on_transact:path),
proxy: $proxy:ident,
+ $(async: $async_interface:ident,)?
}
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {},
+ $(async: $async_interface,)?
stability: $crate::Stability::default(),
}
}
@@ -728,6 +730,7 @@
$interface:path[$descriptor:expr] {
native: $native:ident($on_transact:path),
proxy: $proxy:ident,
+ $(async: $async_interface:ident,)?
stability: $stability:expr,
}
} => {
@@ -735,6 +738,7 @@
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {},
+ $(async: $async_interface,)?
stability: $stability,
}
}
@@ -746,6 +750,7 @@
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
+ $(async: $async_interface:ident,)?
}
} => {
$crate::declare_binder_interface! {
@@ -754,6 +759,7 @@
proxy: $proxy {
$($fname: $fty = $finit),*
},
+ $(async: $async_interface,)?
stability: $crate::Stability::default(),
}
}
@@ -765,6 +771,7 @@
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
+ $(async: $async_interface:ident,)?
stability: $stability:expr,
}
} => {
@@ -776,6 +783,7 @@
proxy: $proxy {
$($fname: $fty = $finit),*
},
+ $(async: $async_interface,)?
stability: $stability,
}
}
@@ -791,6 +799,8 @@
$($fname:ident: $fty:ty = $finit:expr),*
},
+ $( async: $async_interface:ident, )?
+
stability: $stability:expr,
}
} => {
@@ -924,7 +934,7 @@
}
}
- impl std::fmt::Debug for dyn $interface {
+ impl std::fmt::Debug for dyn $interface + '_ {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.pad(stringify!($interface))
}
@@ -938,6 +948,73 @@
.expect(concat!("Error cloning interface ", stringify!($interface)))
}
}
+
+ $(
+ // Async interface trait implementations.
+ impl<P: $crate::BinderAsyncPool> $crate::FromIBinder for dyn $async_interface<P> {
+ fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $async_interface<P>>> {
+ use $crate::AssociateClass;
+
+ let existing_class = ibinder.get_class();
+ if let Some(class) = existing_class {
+ if class != <$native as $crate::Remotable>::get_class() &&
+ class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
+ {
+ // The binder object's descriptor string matches what we
+ // expect. We still need to treat this local or already
+ // associated object as remote, because we can't cast it
+ // into a Rust service object without a matching class
+ // pointer.
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
+ }
+ }
+
+ if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
+ let service: $crate::Result<$crate::Binder<$native>> =
+ std::convert::TryFrom::try_from(ibinder.clone());
+ if let Ok(service) = service {
+ // We were able to associate with our expected class and
+ // the service is local.
+ todo!()
+ //return Ok($crate::Strong::new(Box::new(service)));
+ } else {
+ // Service is remote
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
+ }
+ }
+
+ Err($crate::StatusCode::BAD_TYPE.into())
+ }
+ }
+
+ impl<P: $crate::BinderAsyncPool> $crate::parcel::Serialize for dyn $async_interface<P> + '_ {
+ fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ let binder = $crate::Interface::as_binder(self);
+ parcel.write(&binder)
+ }
+ }
+
+ impl<P: $crate::BinderAsyncPool> $crate::parcel::SerializeOption for dyn $async_interface<P> + '_ {
+ fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ parcel.write(&this.map($crate::Interface::as_binder))
+ }
+ }
+
+ impl<P: $crate::BinderAsyncPool> std::fmt::Debug for dyn $async_interface<P> + '_ {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.pad(stringify!($async_interface))
+ }
+ }
+
+ /// Convert a &dyn $async_interface to Strong<dyn $async_interface>
+ impl<P: $crate::BinderAsyncPool> std::borrow::ToOwned for dyn $async_interface<P> {
+ type Owned = $crate::Strong<dyn $async_interface<P>>;
+ fn to_owned(&self) -> Self::Owned {
+ self.as_binder().into_interface()
+ .expect(concat!("Error cloning interface ", stringify!($async_interface)))
+ }
+ }
+ )?
};
}
diff --git a/libs/binder/rust/src/binder_async.rs b/libs/binder/rust/src/binder_async.rs
new file mode 100644
index 0000000..214c0b5
--- /dev/null
+++ b/libs/binder/rust/src/binder_async.rs
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::future::Future;
+use std::pin::Pin;
+
+/// A type alias for a pinned, boxed future that lets you write shorter code without littering it
+/// with Pin and Send bounds.
+pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
+
+/// A thread pool for running binder transactions.
+pub trait BinderAsyncPool {
+ /// This function should conceptually behave like this:
+ ///
+ /// ```text
+ /// let result = spawn_thread(|| spawn_me()).await;
+ /// return after_spawn(result).await;
+ /// ```
+ ///
+ /// If the spawning fails for some reason, the method may also skip the `after_spawn` closure
+ /// and immediately return an error.
+ ///
+ /// The only difference between different implementations should be which
+ /// `spawn_thread` method is used. For Tokio, it would be `tokio::task::spawn_blocking`.
+ ///
+ /// This method has the design it has because the only way to define a trait that
+ /// allows the return type of the spawn to be chosen by the caller is to return a
+ /// boxed `Future` trait object, and including `after_spawn` in the trait function
+ /// allows the caller to avoid double-boxing if they want to do anything to the value
+ /// returned from the spawned thread.
+ fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+ where
+ F1: FnOnce() -> A,
+ F2: FnOnce(A) -> Fut,
+ Fut: Future<Output = Result<B, E>>,
+ F1: Send + 'static,
+ F2: Send + 'a,
+ Fut: Send + 'a,
+ A: Send + 'static,
+ B: Send + 'a,
+ E: From<crate::StatusCode>;
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index d1d37d7..2ac2d2f 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -98,6 +98,7 @@
#[macro_use]
mod binder;
+mod binder_async;
mod error;
mod native;
mod state;
@@ -111,9 +112,10 @@
Stability, Strong, TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION,
FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
};
+pub use crate::binder_async::{BoxFuture, BinderAsyncPool};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::{add_service, force_lazy_services_persist, register_lazy_service, Binder};
-pub use parcel::Parcel;
+pub use parcel::{OwnedParcel, Parcel};
pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service};
pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
pub use state::{ProcessState, ThreadState};
@@ -133,8 +135,9 @@
wait_for_interface,
};
pub use super::{
- BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
- Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
+ BinderAsyncPool, BinderFeatures, BoxFuture, DeathRecipient, ExceptionCode, IBinder,
+ Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState, Weak,
+ WpIBinder,
};
/// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 7391561..a0e1478 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -23,6 +23,7 @@
use std::cell::RefCell;
use std::convert::TryInto;
+use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ptr;
use std::fmt;
@@ -52,6 +53,119 @@
Borrowed(*mut sys::AParcel),
}
+/// A variant of Parcel that is known to be owned.
+pub struct OwnedParcel {
+ ptr: *mut sys::AParcel,
+}
+
+/// # Safety
+///
+/// This type guarantees that it owns the AParcel and that all access to
+/// the AParcel happens through the OwnedParcel, so it is ok to send across
+/// threads.
+unsafe impl Send for OwnedParcel {}
+
+/// A variant of Parcel that is known to be borrowed.
+pub struct BorrowedParcel<'a> {
+ inner: Parcel,
+ _lifetime: PhantomData<&'a mut Parcel>,
+}
+
+impl OwnedParcel {
+ /// Create a new empty `OwnedParcel`.
+ pub fn new() -> OwnedParcel {
+ let ptr = unsafe {
+ // Safety: If `AParcel_create` succeeds, it always returns
+ // a valid pointer. If it fails, the process will crash.
+ sys::AParcel_create()
+ };
+ assert!(!ptr.is_null());
+ Self { ptr }
+ }
+
+ /// Convert the provided parcel to an owned parcel, or return `None` if it
+ /// is borrowed.
+ pub fn try_from(parcel: Parcel) -> Option<OwnedParcel> {
+ match &parcel {
+ Parcel::Owned(ptr) => {
+ let ptr = *ptr;
+ std::mem::forget(parcel);
+ Some(OwnedParcel { ptr })
+ }
+ Parcel::Borrowed(_) => None,
+ }
+ }
+
+ /// Create an owned reference to a parcel object from a raw pointer.
+ ///
+ /// # Safety
+ ///
+ /// This constructor is safe if the raw pointer parameter is either null
+ /// (resulting in `None`), or a valid pointer to an `AParcel` object. The
+ /// parcel object must be owned by the caller prior to this call, as this
+ /// constructor takes ownership of the parcel and will destroy it on drop.
+ ///
+ /// Additionally, the caller must guarantee that it is valid to take
+ /// ownership of the AParcel object. All future access to the AParcel
+ /// must happen through this `OwnedParcel`.
+ ///
+ /// Because `OwnedParcel` implements `Send`, the pointer must never point
+ /// to any thread-local data, e.g., a variable on the stack, either directly
+ /// or indirectly.
+ pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<OwnedParcel> {
+ ptr.as_mut().map(|ptr| Self { ptr })
+ }
+
+ /// Consume the parcel, transferring ownership to the caller.
+ pub(crate) fn into_raw(self) -> *mut sys::AParcel {
+ let ptr = self.ptr;
+ let _ = ManuallyDrop::new(self);
+ ptr
+ }
+
+ /// Convert this `OwnedParcel` into an owned `Parcel`.
+ pub fn into_parcel(self) -> Parcel {
+ Parcel::Owned(self.into_raw())
+ }
+
+ /// Get a borrowed view into the contents of this `Parcel`.
+ pub fn borrowed(&mut self) -> BorrowedParcel<'_> {
+ BorrowedParcel {
+ inner: Parcel::Borrowed(self.ptr),
+ _lifetime: PhantomData,
+ }
+ }
+}
+
+impl Default for OwnedParcel {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl Clone for OwnedParcel {
+ fn clone(&self) -> Self {
+ let mut new_parcel = Self::new();
+ new_parcel
+ .borrowed()
+ .append_all_from(&Parcel::Borrowed(self.ptr))
+ .expect("Failed to append from Parcel");
+ new_parcel
+ }
+}
+
+impl<'a> std::ops::Deref for BorrowedParcel<'a> {
+ type Target = Parcel;
+ fn deref(&self) -> &Parcel {
+ &self.inner
+ }
+}
+impl<'a> std::ops::DerefMut for BorrowedParcel<'a> {
+ fn deref_mut(&mut self) -> &mut Parcel {
+ &mut self.inner
+ }
+}
+
/// # Safety
///
/// The `Parcel` constructors guarantee that a `Parcel` object will always
@@ -95,33 +209,6 @@
pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> {
ptr.as_mut().map(|ptr| Self::Borrowed(ptr))
}
-
- /// Create an owned reference to a parcel object from a raw pointer.
- ///
- /// # Safety
- ///
- /// This constructor is safe if the raw pointer parameter is either null
- /// (resulting in `None`), or a valid pointer to an `AParcel` object. The
- /// parcel object must be owned by the caller prior to this call, as this
- /// constructor takes ownership of the parcel and will destroy it on drop.
- pub(crate) unsafe fn owned(ptr: *mut sys::AParcel) -> Option<Parcel> {
- ptr.as_mut().map(|ptr| Self::Owned(ptr))
- }
-
- /// Consume the parcel, transferring ownership to the caller if the parcel
- /// was owned.
- pub(crate) fn into_raw(mut self) -> *mut sys::AParcel {
- let ptr = self.as_native_mut();
- let _ = ManuallyDrop::new(self);
- ptr
- }
-
- pub(crate) fn is_owned(&self) -> bool {
- match *self {
- Self::Owned(_) => true,
- Self::Borrowed(_) => false,
- }
- }
}
impl Default for Parcel {
@@ -478,6 +565,18 @@
}
}
+impl Drop for OwnedParcel {
+ fn drop(&mut self) {
+ // Run the C++ Parcel complete object destructor
+ unsafe {
+ // Safety: `OwnedParcel` always contains a valid pointer to an
+ // `AParcel`. Since we own the parcel, we can safely delete it
+ // here.
+ sys::AParcel_delete(self.ptr)
+ }
+ }
+}
+
impl fmt::Debug for Parcel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Parcel")
@@ -485,6 +584,13 @@
}
}
+impl fmt::Debug for OwnedParcel {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedParcel")
+ .finish()
+ }
+}
+
#[test]
fn test_read_write() {
let mut parcel = Parcel::new();
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index f71a686..8bcc5d0 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -94,8 +94,6 @@
}
}
-impl SerializeArray for Option<ParcelFileDescriptor> {}
-
impl DeserializeOption for ParcelFileDescriptor {
fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
let mut fd = -1i32;
@@ -126,8 +124,6 @@
}
}
-impl DeserializeArray for Option<ParcelFileDescriptor> {}
-
impl Deserialize for ParcelFileDescriptor {
fn deserialize(parcel: &Parcel) -> Result<Self> {
Deserialize::deserialize(parcel)
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 499ef09..db9d8b0 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -383,6 +383,9 @@
};
}
+impl<T: DeserializeOption> DeserializeArray for Option<T> {}
+impl<T: SerializeOption> SerializeArray for Option<T> {}
+
parcelable_primitives! {
impl Serialize for bool = sys::AParcel_writeBool;
impl Deserialize for bool = sys::AParcel_readBool;
@@ -537,8 +540,6 @@
}
}
-impl SerializeArray for Option<&str> {}
-
impl Serialize for str {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
Some(self).serialize(parcel)
@@ -561,8 +562,6 @@
}
}
-impl SerializeArray for Option<String> {}
-
impl Deserialize for Option<String> {
fn deserialize(parcel: &Parcel) -> Result<Self> {
let mut vec: Option<Vec<u8>> = None;
@@ -703,6 +702,8 @@
}
}
+impl<T: Serialize + FromIBinder + ?Sized> SerializeArray for Strong<T> {}
+
impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
fn deserialize(parcel: &Parcel) -> Result<Self> {
let ibinder: SpIBinder = parcel.read()?;
@@ -717,6 +718,8 @@
}
}
+impl<T: FromIBinder + ?Sized> DeserializeArray for Strong<T> {}
+
// We need these to support Option<&T> for all T
impl<T: Serialize + ?Sized> Serialize for &T {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index 3e75d1b..bccfd2d 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -16,13 +16,12 @@
use crate::binder::Stability;
use crate::error::{Result, StatusCode};
-use crate::parcel::{Parcel, Parcelable};
+use crate::parcel::{OwnedParcel, Parcel, Parcelable};
use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};
-use downcast_rs::{impl_downcast, Downcast};
+use downcast_rs::{impl_downcast, DowncastSync};
use std::any::Any;
-use std::cell::RefCell;
-use std::rc::Rc;
+use std::sync::{Arc, Mutex};
/// Metadata that `ParcelableHolder` needs for all parcelables.
///
@@ -40,18 +39,18 @@
}
}
-trait AnyParcelable: Downcast + Parcelable + std::fmt::Debug {}
-impl_downcast!(AnyParcelable);
-impl<T> AnyParcelable for T where T: Downcast + Parcelable + std::fmt::Debug {}
+trait AnyParcelable: DowncastSync + Parcelable + std::fmt::Debug {}
+impl_downcast!(sync AnyParcelable);
+impl<T> AnyParcelable for T where T: DowncastSync + Parcelable + std::fmt::Debug {}
#[derive(Debug, Clone)]
enum ParcelableHolderData {
Empty,
Parcelable {
- parcelable: Rc<dyn AnyParcelable>,
+ parcelable: Arc<dyn AnyParcelable>,
name: String,
},
- Parcel(Parcel),
+ Parcel(OwnedParcel),
}
impl Default for ParcelableHolderData {
@@ -67,15 +66,15 @@
/// `ParcelableHolder` is currently not thread-safe (neither
/// `Send` nor `Sync`), mainly because it internally contains
/// a `Parcel` which in turn is not thread-safe.
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Default)]
pub struct ParcelableHolder {
- // This is a `RefCell` because of `get_parcelable`
+ // This is a `Mutex` because of `get_parcelable`
// which takes `&self` for consistency with C++.
// We could make `get_parcelable` take a `&mut self`
- // and get rid of the `RefCell` here for a performance
+ // and get rid of the `Mutex` here for a performance
// improvement, but then callers would require a mutable
// `ParcelableHolder` even for that getter method.
- data: RefCell<ParcelableHolderData>,
+ data: Mutex<ParcelableHolderData>,
stability: Stability,
}
@@ -83,7 +82,7 @@
/// Construct a new `ParcelableHolder` with the given stability.
pub fn new(stability: Stability) -> Self {
Self {
- data: RefCell::new(ParcelableHolderData::Empty),
+ data: Mutex::new(ParcelableHolderData::Empty),
stability,
}
}
@@ -93,20 +92,20 @@
/// Note that this method does not reset the stability,
/// only the contents.
pub fn reset(&mut self) {
- *self.data.get_mut() = ParcelableHolderData::Empty;
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
// We could also clear stability here, but C++ doesn't
}
/// Set the parcelable contained in this `ParcelableHolder`.
- pub fn set_parcelable<T>(&mut self, p: Rc<T>) -> Result<()>
+ pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
where
- T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug,
+ T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
{
if self.stability > p.get_stability() {
return Err(StatusCode::BAD_VALUE);
}
- *self.data.get_mut() = ParcelableHolderData::Parcelable {
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
parcelable: p,
name: T::get_descriptor().into(),
};
@@ -127,12 +126,12 @@
/// * `Ok(None)` if the holder is empty or the descriptor does not match
/// * `Ok(Some(_))` if the object holds a parcelable of type `T`
/// with the correct descriptor
- pub fn get_parcelable<T>(&self) -> Result<Option<Rc<T>>>
+ pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>>
where
- T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug,
+ T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
{
let parcelable_desc = T::get_descriptor();
- let mut data = self.data.borrow_mut();
+ let mut data = self.data.lock().unwrap();
match *data {
ParcelableHolderData::Empty => Ok(None),
ParcelableHolderData::Parcelable {
@@ -143,12 +142,13 @@
return Err(StatusCode::BAD_VALUE);
}
- match Rc::clone(parcelable).downcast_rc::<T>() {
+ match Arc::clone(parcelable).downcast_arc::<T>() {
Err(_) => Err(StatusCode::BAD_VALUE),
Ok(x) => Ok(Some(x)),
}
}
- ParcelableHolderData::Parcel(ref parcel) => {
+ ParcelableHolderData::Parcel(ref mut parcel) => {
+ let parcel = parcel.borrowed();
unsafe {
// Safety: 0 should always be a valid position.
parcel.set_data_position(0)?;
@@ -160,10 +160,10 @@
}
let mut parcelable = T::default();
- parcelable.read_from_parcel(parcel)?;
+ parcelable.read_from_parcel(&parcel)?;
- let parcelable = Rc::new(parcelable);
- let result = Rc::clone(&parcelable);
+ let parcelable = Arc::new(parcelable);
+ let result = Arc::clone(&parcelable);
*data = ParcelableHolderData::Parcelable { parcelable, name };
Ok(Some(result))
@@ -184,7 +184,8 @@
fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
parcel.write(&self.stability)?;
- match *self.data.borrow() {
+ let mut data = self.data.lock().unwrap();
+ match *data {
ParcelableHolderData::Empty => parcel.write(&0i32),
ParcelableHolderData::Parcelable {
ref parcelable,
@@ -212,9 +213,10 @@
Ok(())
}
- ParcelableHolderData::Parcel(ref p) => {
+ ParcelableHolderData::Parcel(ref mut p) => {
+ let p = p.borrowed();
parcel.write(&p.get_data_size())?;
- parcel.append_all_from(p)
+ parcel.append_all_from(&p)
}
}
}
@@ -229,7 +231,7 @@
return Err(StatusCode::BAD_VALUE);
}
if data_size == 0 {
- *self.data.get_mut() = ParcelableHolderData::Empty;
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
return Ok(());
}
@@ -240,9 +242,11 @@
.checked_add(data_size)
.ok_or(StatusCode::BAD_VALUE)?;
- let mut new_parcel = Parcel::new();
- new_parcel.append_from(parcel, data_start, data_size)?;
- *self.data.get_mut() = ParcelableHolderData::Parcel(new_parcel);
+ let mut new_parcel = OwnedParcel::new();
+ new_parcel
+ .borrowed()
+ .append_from(parcel, data_start, data_size)?;
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
unsafe {
// Safety: `append_from` checks if `data_size` overflows
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 6a4af07..a8d0c33 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,7 +22,7 @@
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
- Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+ Deserialize, DeserializeArray, DeserializeOption, OwnedParcel, Parcel, Serialize, SerializeArray,
SerializeOption,
};
use crate::sys;
@@ -235,7 +235,7 @@
}
impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
- fn prepare_transact(&self) -> Result<Parcel> {
+ fn prepare_transact(&self) -> Result<OwnedParcel> {
let mut input = ptr::null_mut();
let status = unsafe {
// Safety: `SpIBinder` guarantees that `self` always contains a
@@ -253,20 +253,19 @@
unsafe {
// Safety: At this point, `input` is either a valid, owned `AParcel`
- // pointer, or null. `Parcel::owned` safely handles both cases,
+ // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
// taking ownership of the parcel.
- Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)
+ OwnedParcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
}
}
fn submit_transact(
&self,
code: TransactionCode,
- data: Parcel,
+ data: OwnedParcel,
flags: TransactionFlags,
- ) -> Result<Parcel> {
+ ) -> Result<OwnedParcel> {
let mut reply = ptr::null_mut();
- assert!(data.is_owned());
let status = unsafe {
// Safety: `SpIBinder` guarantees that `self` always contains a
// valid pointer to an `AIBinder`. Although `IBinder::transact` is
@@ -299,9 +298,8 @@
// after the call to `AIBinder_transact` above, so we can
// construct a `Parcel` out of it. `AIBinder_transact` passes
// ownership of the `reply` parcel to Rust, so we need to
- // construct an owned variant. `Parcel::owned` takes ownership
- // of the parcel pointer.
- Parcel::owned(reply).ok_or(StatusCode::UNEXPECTED_NULL)
+ // construct an owned variant.
+ OwnedParcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
}
}
@@ -429,8 +427,6 @@
}
impl SerializeArray for SpIBinder {}
-impl SerializeArray for Option<&SpIBinder> {}
-impl SerializeArray for Option<SpIBinder> {}
impl Deserialize for SpIBinder {
fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
@@ -448,7 +444,6 @@
}
impl DeserializeArray for SpIBinder {}
-impl DeserializeArray for Option<SpIBinder> {}
/// A weak reference to a Binder remote object.
///
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 0e05f10..0aef744 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -99,6 +99,17 @@
}
}
+ /// Determine whether the current thread is currently executing an incoming transaction.
+ ///
+ /// \return true if the current thread is currently executing an incoming transaction, and false
+ /// otherwise.
+ pub fn is_handling_transaction() -> bool {
+ unsafe {
+ // Safety: Safe FFI
+ sys::AIBinder_isHandlingTransaction()
+ }
+ }
+
/// This function makes the client's security context available to the
/// service calling this function. This can be used for access control.
/// It does not suffer from the TOCTOU issues of get_calling_pid.
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index ecc61f4..2d1175b 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -13,6 +13,8 @@
rustlibs: [
"libbinder_rs",
"libselinux_bindgen",
+ "libbinder_tokio_rs",
+ "libtokio",
],
shared_libs: [
"libselinux",
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 335e8d8..ebfe879 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -17,7 +17,7 @@
//! Rust Binder crate integration tests
use binder::declare_binder_interface;
-use binder::parcel::Parcel;
+use binder::parcel::{Parcel, OwnedParcel};
use binder::{
Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
FIRST_CALL_TRANSACTION,
@@ -154,12 +154,25 @@
fn get_selinux_context(&self) -> binder::Result<String>;
}
+/// Async trivial testing binder interface
+pub trait IATest<P>: Interface {
+ /// Returns a test string
+ fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>>;
+
+ /// Return the arguments sent via dump
+ fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>>;
+
+ /// Returns the caller's SELinux context
+ fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>>;
+}
+
declare_binder_interface! {
ITest["android.os.ITest"] {
native: BnTest(on_transact),
proxy: BpTest {
x: i32 = 100
},
+ async: IATest,
}
}
@@ -201,6 +214,32 @@
}
}
+impl<P: binder::BinderAsyncPool> IATest<P> for BpTest {
+ fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+ let binder = self.binder.clone();
+ P::spawn(
+ move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
+ |reply| async move { reply?.into_parcel().read() }
+ )
+ }
+
+ fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>> {
+ let binder = self.binder.clone();
+ P::spawn(
+ move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
+ |reply| async move { reply?.into_parcel().read() }
+ )
+ }
+
+ fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+ let binder = self.binder.clone();
+ P::spawn(
+ move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
+ |reply| async move { reply?.into_parcel().read() }
+ )
+ }
+}
+
impl ITest for Binder<BnTest> {
fn test(&self) -> binder::Result<String> {
self.0.test()
@@ -215,6 +254,23 @@
}
}
+impl<P: binder::BinderAsyncPool> IATest<P> for Binder<BnTest> {
+ fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+ let res = self.0.test();
+ Box::pin(async move { res })
+ }
+
+ fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>> {
+ let res = self.0.get_dump_args();
+ Box::pin(async move { res })
+ }
+
+ fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+ let res = self.0.get_selinux_context();
+ Box::pin(async move { res })
+ }
+}
+
/// Trivial testing binder interface
pub trait ITestSameDescriptor: Interface {}
@@ -255,7 +311,9 @@
SpIBinder, StatusCode, Strong,
};
- use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
+ use binder_tokio::Tokio;
+
+ use super::{BnTest, ITest, IATest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
pub struct ScopedServiceProcess(Child);
@@ -303,12 +361,47 @@
binder::get_interface::<dyn ITest>("this_service_does_not_exist").err(),
Some(StatusCode::NAME_NOT_FOUND)
);
+ assert_eq!(
+ binder::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").err(),
+ Some(StatusCode::NAME_NOT_FOUND)
+ );
// The service manager service isn't an ITest, so this must fail.
assert_eq!(
binder::get_interface::<dyn ITest>("manager").err(),
Some(StatusCode::BAD_TYPE)
);
+ assert_eq!(
+ binder::get_interface::<dyn IATest<Tokio>>("manager").err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ }
+
+ #[tokio::test]
+ async fn check_services_async() {
+ let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
+ assert!(sm.is_binder_alive());
+ assert!(sm.ping_binder().is_ok());
+
+ assert!(binder::get_service("this_service_does_not_exist").is_none());
+ assert_eq!(
+ binder_tokio::get_interface::<dyn ITest>("this_service_does_not_exist").await.err(),
+ Some(StatusCode::NAME_NOT_FOUND)
+ );
+ assert_eq!(
+ binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").await.err(),
+ Some(StatusCode::NAME_NOT_FOUND)
+ );
+
+ // The service manager service isn't an ITest, so this must fail.
+ assert_eq!(
+ binder_tokio::get_interface::<dyn ITest>("manager").await.err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ assert_eq!(
+ binder_tokio::get_interface::<dyn IATest<Tokio>>("manager").await.err(),
+ Some(StatusCode::BAD_TYPE)
+ );
}
#[test]
@@ -323,6 +416,10 @@
binder::wait_for_interface::<dyn ITest>("manager").err(),
Some(StatusCode::BAD_TYPE)
);
+ assert_eq!(
+ binder::wait_for_interface::<dyn IATest<Tokio>>("manager").err(),
+ Some(StatusCode::BAD_TYPE)
+ );
}
#[test]
@@ -334,6 +431,15 @@
assert_eq!(test_client.test().unwrap(), "trivial_client_test");
}
+ #[tokio::test]
+ async fn trivial_client_async() {
+ let service_name = "trivial_client_test";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn IATest<Tokio>> =
+ binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
+ }
+
#[test]
fn wait_for_trivial_client() {
let service_name = "wait_for_trivial_client_test";
@@ -343,23 +449,47 @@
assert_eq!(test_client.test().unwrap(), "wait_for_trivial_client_test");
}
+ #[tokio::test]
+ async fn wait_for_trivial_client_async() {
+ let service_name = "wait_for_trivial_client_test";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn IATest<Tokio>> =
+ binder_tokio::wait_for_interface(service_name).await.expect("Did not get manager binder service");
+ assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
+ }
+
+ fn get_expected_selinux_context() -> &'static str {
+ unsafe {
+ let mut out_ptr = ptr::null_mut();
+ assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
+ assert!(!out_ptr.is_null());
+ CStr::from_ptr(out_ptr)
+ .to_str()
+ .expect("context was invalid UTF-8")
+ }
+ }
+
#[test]
fn get_selinux_context() {
let service_name = "get_selinux_context";
let _process = ScopedServiceProcess::new(service_name);
let test_client: Strong<dyn ITest> =
binder::get_interface(service_name).expect("Did not get manager binder service");
- let expected_context = unsafe {
- let mut out_ptr = ptr::null_mut();
- assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
- assert!(!out_ptr.is_null());
- CStr::from_ptr(out_ptr)
- };
assert_eq!(
test_client.get_selinux_context().unwrap(),
- expected_context
- .to_str()
- .expect("context was invalid UTF-8"),
+ get_expected_selinux_context()
+ );
+ }
+
+ #[tokio::test]
+ async fn get_selinux_context_async() {
+ let service_name = "get_selinux_context";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn IATest<Tokio>> =
+ binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ assert_eq!(
+ test_client.get_selinux_context().await.unwrap(),
+ get_expected_selinux_context()
);
}
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 23e34aa..777f3c9 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -90,7 +90,6 @@
LOG(ERROR) << "Cannot create RpcServer";
return EX_SOFTWARE;
}
- rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
LOG(ERROR) << "setupInetServer failed: " << statusToString(status);
@@ -207,7 +206,6 @@
service = ServiceManagerProxyToNative::asBinder(interface);
auto rpcServer = RpcServer::make();
- rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
rpcServer->setRootObject(service);
unsigned int port;
if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index 9e10788..fdd02a4 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -18,6 +18,9 @@
oneway void sendString(@utf8InCpp String str);
@utf8InCpp String doubleString(@utf8InCpp String str);
+ // get the port that a client used to connect to this object
+ int getClientPort();
+
// number of known RPC binders to process, RpcState::countBinders by session
int[] countBinders();
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index c69203b..63a4b2c 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -112,7 +112,7 @@
BINDER_LIB_TEST_NOP_TRANSACTION_WAIT,
BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_ECHO_VECTOR,
- BINDER_LIB_TEST_REJECT_BUF,
+ BINDER_LIB_TEST_REJECT_OBJECTS,
BINDER_LIB_TEST_CAN_GET_SID,
};
@@ -436,6 +436,11 @@
};
};
+TEST_F(BinderLibTest, CannotUseBinderAfterFork) {
+ // EXPECT_DEATH works by forking the process
+ EXPECT_DEATH({ ProcessState::self(); }, "libbinder ProcessState can not be used after fork");
+}
+
TEST_F(BinderLibTest, WasParceled) {
auto binder = sp<BBinder>::make();
EXPECT_FALSE(binder->wasParceled());
@@ -1161,13 +1166,53 @@
memcpy(parcelData, &obj, sizeof(obj));
data.setDataSize(sizeof(obj));
+ EXPECT_EQ(data.objectsCount(), 1);
+
// Either the kernel should reject this transaction (if it's correct), but
// if it's not, the server implementation should return an error if it
// finds an object in the received Parcel.
- EXPECT_THAT(server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply),
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_REJECT_OBJECTS, data, &reply),
Not(StatusEq(NO_ERROR)));
}
+TEST_F(BinderLibTest, WeakRejected) {
+ Parcel data, reply;
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+
+ auto binder = sp<BBinder>::make();
+ wp<BBinder> wpBinder(binder);
+ flat_binder_object obj{
+ .hdr = {.type = BINDER_TYPE_WEAK_BINDER},
+ .flags = 0,
+ .binder = reinterpret_cast<uintptr_t>(wpBinder.get_refs()),
+ .cookie = reinterpret_cast<uintptr_t>(wpBinder.unsafe_get()),
+ };
+ data.setDataCapacity(1024);
+ // Write a bogus object at offset 0 to get an entry in the offset table
+ data.writeFileDescriptor(0);
+ EXPECT_EQ(data.objectsCount(), 1);
+ uint8_t *parcelData = const_cast<uint8_t *>(data.data());
+ // And now, overwrite it with the weak binder
+ memcpy(parcelData, &obj, sizeof(obj));
+ data.setDataSize(sizeof(obj));
+
+ // a previous bug caused other objects to be released an extra time, so we
+ // test with an object that libbinder will actually try to release
+ EXPECT_EQ(OK, data.writeStrongBinder(sp<BBinder>::make()));
+
+ EXPECT_EQ(data.objectsCount(), 2);
+
+ // send it many times, since previous error was memory corruption, make it
+ // more likely that the server crashes
+ for (size_t i = 0; i < 100; i++) {
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_REJECT_OBJECTS, data, &reply),
+ StatusEq(BAD_VALUE));
+ }
+
+ EXPECT_THAT(server->pingBinder(), StatusEq(NO_ERROR));
+}
+
TEST_F(BinderLibTest, GotSid) {
sp<IBinder> server = addServer();
@@ -1189,7 +1234,6 @@
auto rpcServer = RpcServer::make();
EXPECT_NE(nullptr, rpcServer);
if (rpcServer == nullptr) return {};
- rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
if (status_t status = rpcServer->setupInetServer("127.0.0.1", 0, &port); status != OK) {
ADD_FAILURE() << "setupInetServer failed" << statusToString(status);
@@ -1562,7 +1606,7 @@
reply->writeUint64Vector(vector);
return NO_ERROR;
}
- case BINDER_LIB_TEST_REJECT_BUF: {
+ case BINDER_LIB_TEST_REJECT_OBJECTS: {
return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR;
}
case BINDER_LIB_TEST_CAN_GET_SID: {
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index f8718aa..52ba9b0 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -206,7 +206,6 @@
if (0 == fork()) {
prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
server->setRootObject(sp<MyBinderRpcBenchmark>::make());
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
CHECK_EQ(OK, server->setupUnixDomainServer(addr));
server->join();
exit(1);
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 8267702..55ad3c6 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -109,7 +109,6 @@
base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
int sinkFd = sink.get();
auto server = RpcServer::make(newFactory(GetParam()));
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
ASSERT_FALSE(server->hasServer());
ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
ASSERT_TRUE(server->hasServer());
@@ -174,6 +173,7 @@
class MyBinderRpcTest : public BnBinderRpcTest {
public:
wp<RpcServer> server;
+ int port = 0;
Status sendString(const std::string& str) override {
(void)str;
@@ -183,6 +183,10 @@
*strstr = str + str;
return Status::ok();
}
+ Status getClientPort(int* out) override {
+ *out = port;
+ return Status::ok();
+ }
Status countBinders(std::vector<int32_t>* out) override {
sp<RpcServer> spServer = server.promote();
if (spServer == nullptr) {
@@ -538,7 +542,6 @@
auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
server->setMaxThreads(options.numThreads);
unsigned int outPort = 0;
@@ -643,13 +646,41 @@
BinderRpcTestProcessSession createRpcTestSocketServerProcess(const Options& options) {
BinderRpcTestProcessSession ret{
- .proc = createRpcTestSocketServerProcess(options,
- [&](const sp<RpcServer>& server) {
- sp<MyBinderRpcTest> service =
- new MyBinderRpcTest;
- server->setRootObject(service);
- service->server = server;
- }),
+ .proc = createRpcTestSocketServerProcess(
+ options,
+ [&](const sp<RpcServer>& server) {
+ server->setPerSessionRootObject([&](const sockaddr* addr,
+ socklen_t len) {
+ sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
+ switch (addr->sa_family) {
+ case AF_UNIX:
+ // nothing to save
+ break;
+ case AF_VSOCK:
+ CHECK_EQ(len, sizeof(sockaddr_vm));
+ service->port = reinterpret_cast<const sockaddr_vm*>(addr)
+ ->svm_port;
+ break;
+ case AF_INET:
+ CHECK_EQ(len, sizeof(sockaddr_in));
+ service->port =
+ ntohs(reinterpret_cast<const sockaddr_in*>(addr)
+ ->sin_port);
+ break;
+ case AF_INET6:
+ CHECK_EQ(len, sizeof(sockaddr_in));
+ service->port =
+ ntohs(reinterpret_cast<const sockaddr_in6*>(addr)
+ ->sin6_port);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unrecognized address family %d",
+ addr->sa_family);
+ }
+ service->server = server;
+ return service;
+ });
+ }),
};
ret.rootBinder = ret.proc.sessions.at(0).root;
@@ -682,6 +713,27 @@
}
}
+TEST_P(BinderRpc, SeparateRootObject) {
+ SocketType type = std::get<0>(GetParam());
+ if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) {
+ // we can't get port numbers for unix sockets
+ return;
+ }
+
+ auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
+
+ int port1 = 0;
+ EXPECT_OK(proc.rootIface->getClientPort(&port1));
+
+ sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
+ int port2;
+ EXPECT_OK(rootIface2->getClientPort(&port2));
+
+ // we should have a different IBinderRpcTest object created for each
+ // session, because we use setPerSessionRootObject
+ EXPECT_NE(port1, port2);
+}
+
TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
auto proc = createRpcTestSocketServerProcess({});
Parcel data;
@@ -1251,11 +1303,20 @@
}
TEST_P(BinderRpc, UseKernelBinderCallingId) {
+ bool okToFork = ProcessState::selfOrNull() == nullptr;
+
auto proc = createRpcTestSocketServerProcess({});
- // we can't allocate IPCThreadState so actually the first time should
- // succeed :(
- EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
+ // If this process has used ProcessState already, then the forked process
+ // cannot use it at all. If this process hasn't used it (depending on the
+ // order tests are run), then the forked process can use it, and we'll only
+ // catch the invalid usage the second time. Such is the burden of global
+ // state!
+ if (okToFork) {
+ // we can't allocate IPCThreadState so actually the first time should
+ // succeed :(
+ EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
+ }
// second time! we catch the error :)
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
@@ -1307,11 +1368,20 @@
ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
}
+TEST_P(BinderRpc, AidlDelegatorTest) {
+ auto proc = createRpcTestSocketServerProcess({});
+ auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
+ ASSERT_NE(nullptr, myDelegator);
+
+ std::string doubled;
+ EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
+ EXPECT_EQ("cool cool ", doubled);
+}
+
static bool testSupportVsockLoopback() {
// We don't need to enable TLS to know if vsock is supported.
unsigned int vsockPort = allocateVsockPort();
sp<RpcServer> server = RpcServer::make(RpcTransportCtxFactoryRaw::make());
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
if (status_t status = server->setupVsockServer(vsockPort); status != OK) {
if (status == -EAFNOSUPPORT) {
return false;
@@ -1400,7 +1470,6 @@
TEST_P(BinderRpcSimple, Shutdown) {
auto addr = allocateSocketAddress();
auto server = RpcServer::make(newFactory(GetParam()));
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
auto joinEnds = std::make_shared<OneOffSignal>();
@@ -1440,7 +1509,6 @@
ASSERT_EQ(OK, binder->pingBinder());
auto rpcServer = RpcServer::make();
- rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
ASSERT_EQ(OK, rpcServer->setupInetServer(kLocalInetAddress, 0, &port));
auto socket = rpcServer->releaseServer();
@@ -1479,7 +1547,6 @@
std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
auto [socketType, rpcSecurity, certificateFormat] = param;
auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
- rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
switch (socketType) {
case SocketType::PRECONNECTED: {
return AssertionFailure() << "Not supported by this test";
@@ -1941,5 +2008,6 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter);
+
return RUN_ALL_TESTS();
}
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 55eb847..32406e5 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -192,6 +192,8 @@
// only reading one binder type for now
PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readStrongBinder),
PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readNullableStrongBinder),
+ PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::os::IServiceManager>>, readStrongBinderVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::sp<android::os::IServiceManager>>>, readStrongBinderVector),
PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
PARCEL_READ_WITH_STATUS(::std::optional<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
@@ -284,7 +286,6 @@
FUZZ_LOG() << "readObject: " << obj;
},
PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
- PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
// additional parcelable objects defined in libbinder
@@ -306,7 +307,16 @@
size_t offset = p.readUint32();
size_t length = p.readUint32();
bool result;
- status_t status = p.hasFileDescriptorsInRange(offset, length, result);
+ status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
+ FUZZ_LOG() << " status: " << status << " result: " << result;
+ },
+ [] (const ::android::Parcel& p, uint8_t /* data */) {
+ FUZZ_LOG() << "about to call compareDataInRange() with status";
+ size_t thisOffset = p.readUint32();
+ size_t otherOffset = p.readUint32();
+ size_t length = p.readUint32();
+ int result;
+ status_t status = p.compareDataInRange(thisOffset, p, otherOffset, length, &result);
FUZZ_LOG() << " status: " << status << " result: " << result;
},
};
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 6b783a4..752fcbb 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -25,6 +25,7 @@
// TODO(b/142061461): parent class
class SomeParcelable {
public:
+ binder_status_t writeToParcel(AParcel* /*parcel*/) { return STATUS_OK; }
binder_status_t readFromParcel(const AParcel* parcel) {
return AParcel_readInt32(parcel, &mValue);
}
@@ -33,6 +34,41 @@
int32_t mValue = 0;
};
+class ISomeInterface : public ::ndk::ICInterface {
+public:
+ ISomeInterface() = default;
+ virtual ~ISomeInterface() = default;
+ static binder_status_t readFromParcel(const AParcel* parcel,
+ std::shared_ptr<ISomeInterface>* instance);
+};
+
+static binder_status_t onTransact(AIBinder*, transaction_code_t, const AParcel*, AParcel*) {
+ return STATUS_UNKNOWN_TRANSACTION;
+}
+
+static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact);
+
+class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> {
+public:
+ explicit BpSomeInterface(const ::ndk::SpAIBinder& binder) : BpCInterface(binder) {}
+ virtual ~BpSomeInterface() = default;
+};
+
+binder_status_t ISomeInterface::readFromParcel(const AParcel* parcel,
+ std::shared_ptr<ISomeInterface>* instance) {
+ ::ndk::SpAIBinder binder;
+ binder_status_t status = AParcel_readStrongBinder(parcel, binder.getR());
+ if (status == STATUS_OK) {
+ if (AIBinder_associateClass(binder.get(), g_class)) {
+ *instance = std::static_pointer_cast<ISomeInterface>(
+ ::ndk::ICInterface::asInterface(binder.get()));
+ } else {
+ *instance = ::ndk::SharedRefBase::make<BpSomeInterface>(binder);
+ }
+ }
+ return status;
+}
+
#define PARCEL_READ(T, FUN) \
[](const NdkParcelAdapter& p, uint8_t /*data*/) { \
FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
@@ -95,6 +131,13 @@
PARCEL_READ(std::vector<std::string>, ndk::AParcel_readVector),
PARCEL_READ(std::optional<std::vector<std::optional<std::string>>>, ndk::AParcel_readVector),
PARCEL_READ(std::vector<SomeParcelable>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<std::optional<SomeParcelable>>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<ndk::SpAIBinder>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<ndk::SpAIBinder>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<ndk::ScopedFileDescriptor>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<ndk::ScopedFileDescriptor>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<std::shared_ptr<ISomeInterface>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<std::shared_ptr<ISomeInterface>>>, ndk::AParcel_readVector),
PARCEL_READ(std::vector<int32_t>, ndk::AParcel_readVector),
PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_readVector),
PARCEL_READ(std::vector<uint32_t>, ndk::AParcel_readVector),
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index c0f0a12..71e847f 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -14,6 +14,7 @@
fuzz_config: {
cc: ["smoreland@google.com"],
},
+ corpus: ["corpus/*"],
dictionary: "binder_rpc_fuzzer.dict",
srcs: [
diff --git a/libs/binder/tests/rpc_fuzzer/corpus/special_transaction b/libs/binder/tests/rpc_fuzzer/corpus/special_transaction
new file mode 100644
index 0000000..37228ee
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/corpus/special_transaction
Binary files differ
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 518849a..a8713a2 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -119,7 +119,6 @@
sp<RpcServer> server = RpcServer::make(makeTransportCtxFactory(&provider));
server->setRootObject(sp<SomeBinder>::make());
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
CHECK_EQ(OK, server->setupUnixDomainServer(kSock.c_str()));
std::thread serverThread([=] { (void)server->join(); });
@@ -158,6 +157,8 @@
}
}
+ usleep(10000);
+
if (hangupBeforeShutdown) {
connections.clear();
while (!server->listSessions().empty() || server->numUninitializedSessions()) {
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index 20c5569..e77c55c 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -44,7 +44,6 @@
auto thread = std::thread([&]() {
prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
server->setRootObject(sp<BBinder>::make());
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
server->join();
});
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 8c359c7..19a29c1 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -208,7 +208,6 @@
],
shared_libs: [
- "android.frameworks.bufferhub@1.0",
"libbinder",
"libbufferhub",
"libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
@@ -234,7 +233,6 @@
"BufferHubProducer.cpp",
],
exclude_shared_libs: [
- "android.frameworks.bufferhub@1.0",
"libbufferhub",
"libbufferhubqueue",
"libpdx_default_transport",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dfbb863..9080822 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -296,7 +296,7 @@
flushShadowQueue();
}
} else {
- BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
+ BQA_LOGE("Failed to find matching SurfaceControl in transactionCommittedCallback");
}
} else {
BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
@@ -319,9 +319,6 @@
void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
const std::vector<SurfaceControlStats>& stats) {
- std::function<void(int64_t)> transactionCompleteCallback = nullptr;
- uint64_t currFrameNumber = 0;
-
{
std::unique_lock _lock{mMutex};
ATRACE_CALL();
@@ -348,20 +345,8 @@
stat.latchTime,
stat.frameEventStats.dequeueReadyTime);
}
- currFrameNumber = stat.frameEventStats.frameNumber;
-
- if (mTransactionCompleteCallback &&
- currFrameNumber >= mTransactionCompleteFrameNumber) {
- if (currFrameNumber > mTransactionCompleteFrameNumber) {
- BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64
- " than expected=%" PRIu64,
- currFrameNumber, mTransactionCompleteFrameNumber);
- }
- transactionCompleteCallback = std::move(mTransactionCompleteCallback);
- mTransactionCompleteFrameNumber = 0;
- }
} else {
- BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
+ BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
}
} else {
BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
@@ -370,10 +355,6 @@
decStrong((void*)transactionCallbackThunk);
}
-
- if (transactionCompleteCallback) {
- transactionCompleteCallback(currFrameNumber);
- }
}
// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
@@ -698,17 +679,6 @@
return mSize != bufferSize;
}
-void BLASTBufferQueue::setTransactionCompleteCallback(
- uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback) {
- std::lock_guard _lock{mMutex};
- if (transactionCompleteCallback == nullptr) {
- mTransactionCompleteCallback = nullptr;
- } else {
- mTransactionCompleteCallback = std::move(transactionCompleteCallback);
- mTransactionCompleteFrameNumber = frameNumber;
- }
-}
-
// Check if we have acquired the maximum number of buffers.
// Consumer can acquire an additional buffer if that buffer is not droppable. Set
// includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 30d19e3..b3647d6 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -301,7 +301,7 @@
// continues to use it.
sp<GraphicBuffer> buffer = new GraphicBuffer(
kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
- GraphicBuffer::USAGE_SW_WRITE_RARELY,
+ DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
"[GLConsumer debug texture]");
uint32_t* bits;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 3c8289f..0295099 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1150,41 +1150,6 @@
return reply.readInt32();
}
- status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override {
- if (!outToken) return BAD_VALUE;
-
- Parcel data, reply;
- status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- if (err != NO_ERROR) {
- ALOGE("acquireFrameRateFlexibilityToken: failed writing interface token: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = remote()->transact(BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, data,
- &reply);
- if (err != NO_ERROR) {
- ALOGE("acquireFrameRateFlexibilityToken: failed to transact: %s (%d)", strerror(-err),
- err);
- return err;
- }
-
- err = reply.readInt32();
- if (err != NO_ERROR) {
- ALOGE("acquireFrameRateFlexibilityToken: call failed: %s (%d)", strerror(-err), err);
- return err;
- }
-
- err = reply.readStrongBinder(outToken);
- if (err != NO_ERROR) {
- ALOGE("acquireFrameRateFlexibilityToken: failed reading binder token: %s (%d)",
- strerror(-err), err);
- return err;
- }
-
- return NO_ERROR;
- }
-
status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
const FrameTimelineInfo& frameTimelineInfo) override {
Parcel data, reply;
@@ -2073,16 +2038,6 @@
reply->writeInt32(result);
return NO_ERROR;
}
- case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> token;
- status_t result = acquireFrameRateFlexibilityToken(&token);
- reply->writeInt32(result);
- if (result == NO_ERROR) {
- reply->writeStrongBinder(token);
- }
- return NO_ERROR;
- }
case SET_FRAME_TIMELINE_INFO: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> binder;
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 4a1d475..3881620 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -88,8 +88,8 @@
void onFrameDequeued(const uint64_t) override;
void onFrameCancelled(const uint64_t) override;
- void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
- const std::vector<SurfaceControlStats>& stats);
+ virtual void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats);
void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats);
void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
@@ -97,8 +97,6 @@
void setNextTransaction(SurfaceComposerClient::Transaction *t);
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void applyPendingTransactions(uint64_t frameNumber);
- void setTransactionCompleteCallback(uint64_t frameNumber,
- std::function<void(int64_t)>&& transactionCompleteCallback);
void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format,
SurfaceComposerClient::Transaction* outTransaction = nullptr);
@@ -224,9 +222,6 @@
// Tracks the last acquired frame number
uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0;
- std::function<void(int64_t)> mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr;
- uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0};
-
// Queues up transactions using this token in SurfaceFlinger. This prevents queued up
// transactions from other parts of the client from blocking this transaction.
const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = new BBinder();
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 408497d..e0183ad 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -512,14 +512,6 @@
int8_t compatibility, int8_t changeFrameRateStrategy) = 0;
/*
- * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired,
- * surface flinger will freely switch between frame rates in any way it sees fit, regardless of
- * the current restrictions applied by DisplayManager. This is useful to get consistent behavior
- * for tests. Release the token by releasing the returned IBinder reference.
- */
- virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) = 0;
-
- /*
* Sets the frame timeline vsync info received from choreographer that corresponds to next
* buffer submitted on that surface.
*/
@@ -616,6 +608,7 @@
GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
SET_GAME_CONTENT_TYPE,
SET_FRAME_RATE,
+ // Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
SET_FRAME_TIMELINE_INFO,
ADD_TRANSACTION_TRACE_LISTENER,
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index e540351..40d096e 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -429,11 +429,11 @@
uint32_t mReqHeight;
// mReqFormat is the buffer pixel format that will be requested at the next
- // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
+ // dequeue operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
PixelFormat mReqFormat;
// mReqUsage is the set of buffer usage flags that will be requested
- // at the next deuque operation. It is initialized to 0.
+ // at the next dequeue operation. It is initialized to 0.
uint64_t mReqUsage;
// mTimestamp is the timestamp that will be used for the next buffer queue
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 8e4898d..b2d5048 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -66,11 +66,44 @@
int32_t mNumReleased GUARDED_BY(mMutex) = 0;
};
+class TestBLASTBufferQueue : public BLASTBufferQueue {
+public:
+ TestBLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
+ int height, int32_t format)
+ : BLASTBufferQueue(name, surface, width, height, format) {}
+
+ void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) override {
+ BLASTBufferQueue::transactionCommittedCallback(latchTime, presentFence, stats);
+
+ uint64_t frameNumber = stats[0].frameEventStats.frameNumber;
+
+ {
+ std::unique_lock lock{frameNumberMutex};
+ mLastTransactionCommittedFrameNumber = frameNumber;
+ mCommittedCV.notify_all();
+ }
+ }
+
+ void waitForCallback(int64_t frameNumber) {
+ std::unique_lock lock{frameNumberMutex};
+ // Wait until all but one of the submitted buffers have been released.
+ while (mLastTransactionCommittedFrameNumber < frameNumber) {
+ mCommittedCV.wait(lock);
+ }
+ }
+
+private:
+ std::mutex frameNumberMutex;
+ std::condition_variable mCommittedCV;
+ int64_t mLastTransactionCommittedFrameNumber = -1;
+};
+
class BLASTBufferQueueHelper {
public:
BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) {
- mBlastBufferQueueAdapter = new BLASTBufferQueue("TestBLASTBufferQueue", sc, width, height,
- PIXEL_FORMAT_RGBA_8888);
+ mBlastBufferQueueAdapter = new TestBLASTBufferQueue("TestBLASTBufferQueue", sc, width,
+ height, PIXEL_FORMAT_RGBA_8888);
}
void update(const sp<SurfaceControl>& sc, int width, int height) {
@@ -107,28 +140,12 @@
}
}
- void setTransactionCompleteCallback(int64_t frameNumber) {
- mBlastBufferQueueAdapter->setTransactionCompleteCallback(frameNumber, [&](int64_t frame) {
- std::unique_lock lock{mMutex};
- mLastTransactionCompleteFrameNumber = frame;
- mCallbackCV.notify_all();
- });
- }
-
void waitForCallback(int64_t frameNumber) {
- std::unique_lock lock{mMutex};
- // Wait until all but one of the submitted buffers have been released.
- while (mLastTransactionCompleteFrameNumber < frameNumber) {
- mCallbackCV.wait(lock);
- }
+ mBlastBufferQueueAdapter->waitForCallback(frameNumber);
}
private:
- sp<BLASTBufferQueue> mBlastBufferQueueAdapter;
-
- std::mutex mMutex;
- std::condition_variable mCallbackCV;
- int64_t mLastTransactionCompleteFrameNumber = -1;
+ sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
};
class BLASTBufferQueueTest : public ::testing::Test {
@@ -1366,7 +1383,6 @@
IGraphicBufferProducer::QueueBufferOutput qbOutput;
nsecs_t requestedPresentTimeA = 0;
nsecs_t postedTimeA = 0;
- adapter.setTransactionCompleteCallback(1);
setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
history.applyDelta(qbOutput.frameTimestamps);
@@ -1435,7 +1451,6 @@
// queue another buffer so the first can be dropped
nsecs_t requestedPresentTimeB = 0;
nsecs_t postedTimeB = 0;
- adapter.setTransactionCompleteCallback(2);
presentTime = systemTime() + std::chrono::nanoseconds(1ms).count();
setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true,
presentTime);
@@ -1501,7 +1516,6 @@
IGraphicBufferProducer::QueueBufferOutput qbOutput;
nsecs_t requestedPresentTimeA = 0;
nsecs_t postedTimeA = 0;
- adapter.setTransactionCompleteCallback(1);
setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
history.applyDelta(qbOutput.frameTimestamps);
adapter.waitForCallback(1);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index a9f4d09..b2baea6 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -885,10 +885,6 @@
return NO_ERROR;
}
- status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) override {
- return NO_ERROR;
- }
-
status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& /*surface*/,
const FrameTimelineInfo& /*frameTimelineInfo*/) override {
return NO_ERROR;
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 390ff96..d018800 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -56,13 +56,8 @@
transformedPoint.y -= origin.y;
// Derive the transformed vector's clockwise angle from vertical.
- float result = atan2f(transformedPoint.x, -transformedPoint.y);
- if (result < -M_PI_2) {
- result += M_PI;
- } else if (result > M_PI_2) {
- result -= M_PI;
- }
- return result;
+ // The return value of atan2f is in range [-pi, pi] which conforms to the orientation API.
+ return atan2f(transformedPoint.x, -transformedPoint.y);
}
vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) {
@@ -498,44 +493,14 @@
float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
size_t historicalIndex) const {
- const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
-
- if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
- const vec2 xy = calculateTransformedXY(mSource, mRawTransform, coords->getXYValue());
- static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
- return xy[axis];
- }
-
- if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
- const vec2 relativeXy =
- transformWithoutTranslation(mRawTransform,
- {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
- coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)});
- return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
- }
-
- return coords->getAxisValue(axis);
+ const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
+ return calculateTransformedAxisValue(axis, mSource, mRawTransform, coords);
}
float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
size_t historicalIndex) const {
- const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
-
- if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
- const vec2 xy = calculateTransformedXY(mSource, mTransform, coords->getXYValue());
- static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
- return xy[axis];
- }
-
- if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
- const vec2 relativeXy =
- transformWithoutTranslation(mTransform,
- {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
- coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)});
- return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
- }
-
- return coords->getAxisValue(axis);
+ const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
+ return calculateTransformedAxisValue(axis, mSource, mTransform, coords);
}
ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
@@ -574,15 +539,6 @@
ui::Transform newTransform;
newTransform.set(matrix);
mTransform = newTransform * mTransform;
-
- // We need to update the AXIS_ORIENTATION value here to maintain the old behavior where the
- // orientation angle is not affected by the initial transformation set in the MotionEvent.
- std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(),
- [&newTransform](PointerCoords& c) {
- float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
- c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
- transformAngle(newTransform, orientation));
- });
}
void MotionEvent::applyTransform(const std::array<float, 9>& matrix) {
@@ -814,6 +770,30 @@
: transform.transform(xy);
}
+float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source,
+ const ui::Transform& transform,
+ const PointerCoords& coords) {
+ if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
+ const vec2 xy = calculateTransformedXY(source, transform, coords.getXYValue());
+ static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
+ return xy[axis];
+ }
+
+ if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
+ const vec2 relativeXy =
+ transformWithoutTranslation(transform,
+ {coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+ coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)});
+ return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
+ }
+
+ if (axis == AMOTION_EVENT_AXIS_ORIENTATION) {
+ return transformAngle(transform, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ }
+
+ return coords.getAxisValue(axis);
+}
+
// --- FocusEvent ---
void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 69ae9a0..015bd81 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -89,8 +89,15 @@
// Treblized input device config files will be located /product/usr, /system_ext/usr,
// /odm/usr or /vendor/usr.
- const char* rootsForPartition[]{"/product", "/system_ext", "/odm", "/vendor",
- getenv("ANDROID_ROOT")};
+ // These files may also be in the com.android.input.config APEX.
+ const char* rootsForPartition[]{
+ "/product",
+ "/system_ext",
+ "/odm",
+ "/vendor",
+ "/apex/com.android.input.config/etc",
+ getenv("ANDROID_ROOT"),
+ };
for (size_t i = 0; i < size(rootsForPartition); i++) {
if (rootsForPartition[i] == nullptr) {
continue;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index a44f0b7..a6465ee 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -18,10 +18,10 @@
//#define LOG_NDEBUG 0
// Log debug messages about velocity tracking.
-#define DEBUG_VELOCITY 0
+static constexpr bool DEBUG_VELOCITY = false;
// Log debug messages about the progress of the algorithm itself.
-#define DEBUG_STRATEGY 0
+static constexpr bool DEBUG_STRATEGY = false;
#include <array>
#include <inttypes.h>
@@ -30,7 +30,6 @@
#include <optional>
#include <android-base/stringprintf.h>
-#include <cutils/properties.h>
#include <input/VelocityTracker.h>
#include <utils/BitSet.h>
#include <utils/Timers.h>
@@ -64,7 +63,6 @@
return sqrtf(r);
}
-#if DEBUG_STRATEGY || DEBUG_VELOCITY
static std::string vectorToString(const float* a, uint32_t m) {
std::string str;
str += "[";
@@ -77,9 +75,11 @@
str += " ]";
return str;
}
-#endif
-#if DEBUG_STRATEGY
+static std::string vectorToString(const std::vector<float>& v) {
+ return vectorToString(v.data(), v.size());
+}
+
static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
std::string str;
str = "[";
@@ -99,7 +99,6 @@
str += " ]";
return str;
}
-#endif
// --- VelocityTracker ---
@@ -133,12 +132,18 @@
VelocityTracker::Strategy strategy) {
switch (strategy) {
case VelocityTracker::Strategy::IMPULSE:
+ if (DEBUG_STRATEGY) {
+ ALOGI("Initializing impulse strategy");
+ }
return std::make_unique<ImpulseVelocityTrackerStrategy>();
case VelocityTracker::Strategy::LSQ1:
return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1);
case VelocityTracker::Strategy::LSQ2:
+ if (DEBUG_STRATEGY) {
+ ALOGI("Initializing lsq2 strategy");
+ }
return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2);
case VelocityTracker::Strategy::LSQ3:
@@ -204,10 +209,10 @@
if ((mCurrentPointerIdBits.value & idBits.value)
&& eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
-#if DEBUG_VELOCITY
- ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
- (eventTime - mLastEventTime) * 0.000001f);
-#endif
+ if (DEBUG_VELOCITY) {
+ ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
+ (eventTime - mLastEventTime) * 0.000001f);
+ }
// We have not received any movements for too long. Assume that all pointers
// have stopped.
mStrategy->clear();
@@ -221,24 +226,24 @@
mStrategy->addMovement(eventTime, idBits, positions);
-#if DEBUG_VELOCITY
- ALOGD("VelocityTracker: addMovement eventTime=%" PRId64 ", idBits=0x%08x, activePointerId=%d",
- eventTime, idBits.value, mActivePointerId);
- for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
- uint32_t id = iterBits.firstMarkedBit();
- uint32_t index = idBits.getIndexOfBit(id);
- iterBits.clearBit(id);
- Estimator estimator;
- getEstimator(id, &estimator);
- ALOGD(" %d: position (%0.3f, %0.3f), "
- "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
- id, positions[index].x, positions[index].y,
- int(estimator.degree),
- vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(),
- vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(),
- estimator.confidence);
+ if (DEBUG_VELOCITY) {
+ ALOGD("VelocityTracker: addMovement eventTime=%" PRId64
+ ", idBits=0x%08x, activePointerId=%d",
+ eventTime, idBits.value, mActivePointerId);
+ for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) {
+ uint32_t id = iterBits.firstMarkedBit();
+ uint32_t index = idBits.getIndexOfBit(id);
+ iterBits.clearBit(id);
+ Estimator estimator;
+ getEstimator(id, &estimator);
+ ALOGD(" %d: position (%0.3f, %0.3f), "
+ "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
+ id, positions[index].x, positions[index].y, int(estimator.degree),
+ vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(),
+ vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(),
+ estimator.confidence);
+ }
}
-#endif
}
void VelocityTracker::addMovement(const MotionEvent* event) {
@@ -419,11 +424,10 @@
static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y,
const std::vector<float>& w, uint32_t n, float* outB, float* outDet) {
const size_t m = x.size();
-#if DEBUG_STRATEGY
- ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
- vectorToString(x, m).c_str(), vectorToString(y, m).c_str(),
- vectorToString(w, m).c_str());
-#endif
+ if (DEBUG_STRATEGY) {
+ ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
+ vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str());
+ }
LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes");
// Expand the X vector to a matrix A, pre-multiplied by the weights.
@@ -434,9 +438,9 @@
a[i][h] = a[i - 1][h] * x[h];
}
}
-#if DEBUG_STRATEGY
- ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
-#endif
+ if (DEBUG_STRATEGY) {
+ ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
+ }
// Apply the Gram-Schmidt process to A to obtain its QR decomposition.
float q[n][m]; // orthonormal basis, column-major order
@@ -455,9 +459,9 @@
float norm = vectorNorm(&q[j][0], m);
if (norm < 0.000001f) {
// vectors are linearly dependent or zero so no solution
-#if DEBUG_STRATEGY
- ALOGD(" - no solution, norm=%f", norm);
-#endif
+ if (DEBUG_STRATEGY) {
+ ALOGD(" - no solution, norm=%f", norm);
+ }
return false;
}
@@ -469,22 +473,22 @@
r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
}
}
-#if DEBUG_STRATEGY
- ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str());
- ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str());
+ if (DEBUG_STRATEGY) {
+ ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str());
+ ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str());
- // calculate QR, if we factored A correctly then QR should equal A
- float qr[n][m];
- for (uint32_t h = 0; h < m; h++) {
- for (uint32_t i = 0; i < n; i++) {
- qr[i][h] = 0;
- for (uint32_t j = 0; j < n; j++) {
- qr[i][h] += q[j][h] * r[j][i];
+ // calculate QR, if we factored A correctly then QR should equal A
+ float qr[n][m];
+ for (uint32_t h = 0; h < m; h++) {
+ for (uint32_t i = 0; i < n; i++) {
+ qr[i][h] = 0;
+ for (uint32_t j = 0; j < n; j++) {
+ qr[i][h] += q[j][h] * r[j][i];
+ }
}
}
+ ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str());
}
- ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str());
-#endif
// Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
// We just work from bottom-right to top-left calculating B's coefficients.
@@ -500,9 +504,9 @@
}
outB[i] /= r[i][i];
}
-#if DEBUG_STRATEGY
- ALOGD(" - b=%s", vectorToString(outB, n).c_str());
-#endif
+ if (DEBUG_STRATEGY) {
+ ALOGD(" - b=%s", vectorToString(outB, n).c_str());
+ }
// Calculate the coefficient of determination as 1 - (SSerr / SStot) where
// SSerr is the residual sum of squares (variance of the error),
@@ -528,11 +532,11 @@
sstot += w[h] * w[h] * var * var;
}
*outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
-#if DEBUG_STRATEGY
- ALOGD(" - sserr=%f", sserr);
- ALOGD(" - sstot=%f", sstot);
- ALOGD(" - det=%f", *outDet);
-#endif
+ if (DEBUG_STRATEGY) {
+ ALOGD(" - sserr=%f", sserr);
+ ALOGD(" - sstot=%f", sstot);
+ ALOGD(" - det=%f", *outDet);
+ }
return true;
}
@@ -655,13 +659,11 @@
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = degree;
outEstimator->confidence = xdet * ydet;
-#if DEBUG_STRATEGY
- ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
- int(outEstimator->degree),
- vectorToString(outEstimator->xCoeff, n).c_str(),
- vectorToString(outEstimator->yCoeff, n).c_str(),
- outEstimator->confidence);
-#endif
+ if (DEBUG_STRATEGY) {
+ ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
+ int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(),
+ vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence);
+ }
return true;
}
}
@@ -1169,9 +1171,9 @@
outEstimator->time = newestMovement.eventTime;
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]);
-#endif
+ if (DEBUG_STRATEGY) {
+ ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+ }
return true;
}
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index caf3a61..1b594f1 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -444,12 +444,19 @@
ASSERT_EQ(217, event->getToolMinor(0));
ASSERT_EQ(227, event->getToolMinor(1));
- ASSERT_EQ(18, event->getHistoricalOrientation(0, 0));
- ASSERT_EQ(28, event->getHistoricalOrientation(1, 0));
- ASSERT_EQ(118, event->getHistoricalOrientation(0, 1));
- ASSERT_EQ(128, event->getHistoricalOrientation(1, 1));
- ASSERT_EQ(218, event->getOrientation(0));
- ASSERT_EQ(228, event->getOrientation(1));
+ // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is "up",
+ // and the positive y direction is "down".
+ auto toScaledOrientation = [](float angle) {
+ const float x = sinf(angle) * X_SCALE;
+ const float y = -cosf(angle) * Y_SCALE;
+ return atan2f(x, -y);
+ };
+ ASSERT_EQ(toScaledOrientation(18), event->getHistoricalOrientation(0, 0));
+ ASSERT_EQ(toScaledOrientation(28), event->getHistoricalOrientation(1, 0));
+ ASSERT_EQ(toScaledOrientation(118), event->getHistoricalOrientation(0, 1));
+ ASSERT_EQ(toScaledOrientation(128), event->getHistoricalOrientation(1, 1));
+ ASSERT_EQ(toScaledOrientation(218), event->getOrientation(0));
+ ASSERT_EQ(toScaledOrientation(228), event->getOrientation(1));
}
TEST_F(MotionEventTest, Properties) {
@@ -518,6 +525,7 @@
TEST_F(MotionEventTest, Scale) {
MotionEvent event;
initializeEventWithHistory(&event);
+ const float unscaledOrientation = event.getOrientation(0);
event.scale(2.0f);
@@ -534,7 +542,7 @@
ASSERT_EQ(215 * 2, event.getTouchMinor(0));
ASSERT_EQ(216 * 2, event.getToolMajor(0));
ASSERT_EQ(217 * 2, event.getToolMinor(0));
- ASSERT_EQ(218, event.getOrientation(0));
+ ASSERT_EQ(unscaledOrientation, event.getOrientation(0));
}
TEST_F(MotionEventTest, Parcel) {
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index d09f2ac..973194c 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -259,7 +259,13 @@
EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i));
EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i));
EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i));
- EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i));
+
+ // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is
+ // "up", and the positive y direction is "down".
+ const float unscaledOrientation = pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+ const float x = sinf(unscaledOrientation) * xScale;
+ const float y = -cosf(unscaledOrientation) * yScale;
+ EXPECT_EQ(atan2f(x, -y), motionEvent->getOrientation(i));
}
status = mConsumer->sendFinishedSignal(seq, false);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 3039362..a87b187 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -343,7 +343,7 @@
{ 235089162955851ns, {{560.66, 843.82}} }, // ACTION_UP
};
computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
- 872.794617);
+ 764.345703);
computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
951.698181);
computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 2f31888..6882ea3 100644
--- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -191,7 +191,7 @@
// continues to use it.
sp<GraphicBuffer> buffer =
new GraphicBuffer(kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
- GraphicBuffer::USAGE_SW_WRITE_RARELY,
+ DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
"[EGLConsumer debug texture]");
uint32_t* bits;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index a299488..0565f42 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -15,6 +15,13 @@
*/
/**
+ * @defgroup ADataSpace Data Space
+ *
+ * ADataSpace describes how to interpret colors.
+ * @{
+ */
+
+/**
* @file data_space.h
*/
@@ -517,3 +524,5 @@
__END_DECLS
#endif // ANDROID_DATA_SPACE_H
+
+/** @} */
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 570c7bc..a62d2b9 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -94,6 +94,8 @@
"skia/debug/SkiaCapture.cpp",
"skia/debug/SkiaMemoryReporter.cpp",
"skia/filters/BlurFilter.cpp",
+ "skia/filters/GaussianBlurFilter.cpp",
+ "skia/filters/KawaseBlurFilter.cpp",
"skia/filters/LinearEffect.cpp",
"skia/filters/StretchShaderFactory.cpp"
],
diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp
new file mode 100644
index 0000000..5968399
--- /dev/null
+++ b/libs/renderengine/benchmark/Android.bp
@@ -0,0 +1,54 @@
+// Copyright 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_benchmark {
+ name: "librenderengine_bench",
+ defaults: ["skia_deps", "surfaceflinger_defaults"],
+ srcs: [
+ "main.cpp",
+ "Codec.cpp",
+ "Flags.cpp",
+ "RenderEngineBench.cpp",
+ ],
+ static_libs: [
+ "librenderengine",
+ ],
+ cflags: [
+ "-DLOG_TAG=\"RenderEngineBench\"",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libjnigraphics",
+ "libgui",
+ "liblog",
+ "libnativewindow",
+ "libprocessgroup",
+ "libsync",
+ "libui",
+ "libutils",
+ ],
+
+ data: [ "resources/*"],
+}
diff --git a/libs/renderengine/benchmark/Codec.cpp b/libs/renderengine/benchmark/Codec.cpp
new file mode 100644
index 0000000..80e4fc4
--- /dev/null
+++ b/libs/renderengine/benchmark/Codec.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#include <RenderEngineBench.h>
+#include <android/bitmap.h>
+#include <android/data_space.h>
+#include <android/imagedecoder.h>
+#include <log/log.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/RenderEngine.h>
+#include <sys/types.h>
+
+using namespace android;
+using namespace android::renderengine;
+
+namespace {
+struct DecoderDeleter {
+ void operator()(AImageDecoder* decoder) { AImageDecoder_delete(decoder); }
+};
+
+using AutoDecoderDeleter = std::unique_ptr<AImageDecoder, DecoderDeleter>;
+
+bool ok(int aImageDecoderResult, const char* path, const char* method) {
+ if (aImageDecoderResult == ANDROID_IMAGE_DECODER_SUCCESS) {
+ return true;
+ }
+
+ ALOGE("Failed AImageDecoder_%s on '%s' with error '%s'", method, path,
+ AImageDecoder_resultToString(aImageDecoderResult));
+ return false;
+}
+} // namespace
+
+namespace renderenginebench {
+
+void decode(const char* path, const sp<GraphicBuffer>& buffer) {
+ base::unique_fd fd{open(path, O_RDONLY)};
+ if (fd.get() < 0) {
+ ALOGE("Failed to open %s", path);
+ return;
+ }
+
+ AImageDecoder* decoder{nullptr};
+ auto result = AImageDecoder_createFromFd(fd.get(), &decoder);
+ if (!ok(result, path, "createFromFd")) {
+ return;
+ }
+
+ AutoDecoderDeleter deleter(decoder);
+
+ LOG_ALWAYS_FATAL_IF(buffer->getWidth() <= 0 || buffer->getHeight() <= 0,
+ "Impossible buffer size!");
+ auto width = static_cast<int32_t>(buffer->getWidth());
+ auto height = static_cast<int32_t>(buffer->getHeight());
+ result = AImageDecoder_setTargetSize(decoder, width, height);
+ if (!ok(result, path, "setTargetSize")) {
+ return;
+ }
+
+ void* pixels{nullptr};
+ int32_t stride{0};
+ if (auto status = buffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &pixels,
+ nullptr /*outBytesPerPixel*/, &stride);
+ status < 0) {
+ ALOGE("Failed to lock pixels!");
+ return;
+ }
+
+ result = AImageDecoder_decodeImage(decoder, pixels, static_cast<size_t>(stride),
+ static_cast<size_t>(stride * height));
+ if (auto status = buffer->unlock(); status < 0) {
+ ALOGE("Failed to unlock pixels!");
+ }
+
+ // For the side effect of logging.
+ (void)ok(result, path, "decodeImage");
+}
+
+void encodeToJpeg(const char* path, const sp<GraphicBuffer>& buffer) {
+ base::unique_fd fd{open(path, O_WRONLY | O_CREAT, S_IWUSR)};
+ if (fd.get() < 0) {
+ ALOGE("Failed to open %s", path);
+ return;
+ }
+
+ void* pixels{nullptr};
+ int32_t stride{0};
+ if (auto status = buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, &pixels,
+ nullptr /*outBytesPerPixel*/, &stride);
+ status < 0) {
+ ALOGE("Failed to lock pixels!");
+ return;
+ }
+
+ AndroidBitmapInfo info{
+ .width = buffer->getWidth(),
+ .height = buffer->getHeight(),
+ .stride = static_cast<uint32_t>(stride),
+ .format = ANDROID_BITMAP_FORMAT_RGBA_8888,
+ .flags = ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE,
+ };
+ int result = AndroidBitmap_compress(&info, ADATASPACE_SRGB, pixels,
+ ANDROID_BITMAP_COMPRESS_FORMAT_JPEG, 80, &fd,
+ [](void* fdPtr, const void* data, size_t size) -> bool {
+ const ssize_t bytesWritten =
+ write(reinterpret_cast<base::unique_fd*>(fdPtr)
+ ->get(),
+ data, size);
+ return bytesWritten > 0 &&
+ static_cast<size_t>(bytesWritten) == size;
+ });
+ if (result == ANDROID_BITMAP_RESULT_SUCCESS) {
+ ALOGD("Successfully encoded to '%s'", path);
+ } else {
+ ALOGE("Failed to encode to %s with error %d", path, result);
+ }
+
+ if (auto status = buffer->unlock(); status < 0) {
+ ALOGE("Failed to unlock pixels!");
+ }
+}
+
+} // namespace renderenginebench
diff --git a/libs/renderengine/benchmark/Flags.cpp b/libs/renderengine/benchmark/Flags.cpp
new file mode 100644
index 0000000..c5d5156
--- /dev/null
+++ b/libs/renderengine/benchmark/Flags.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include <log/log.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace {
+bool gSave = false;
+}
+
+namespace renderenginebench {
+
+void parseFlagsForHelp(int argc, char** argv) {
+ for (int i = 0; i < argc; i++) {
+ if (!strcmp(argv[i], "--help")) {
+ printf("RenderEngineBench-specific flags:\n");
+ printf("[--save]: Save the output to the device to confirm drawing result.\n");
+ break;
+ }
+ }
+}
+
+void parseFlags(int argc, char** argv) {
+ for (int i = 0; i < argc; i++) {
+ if (!strcmp(argv[i], "--save")) {
+ gSave = true;
+ }
+ }
+}
+
+bool save() {
+ return gSave;
+}
+} // namespace renderenginebench
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
new file mode 100644
index 0000000..719b855
--- /dev/null
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+#include <RenderEngineBench.h>
+#include <android-base/file.h>
+#include <benchmark/benchmark.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/LayerSettings.h>
+#include <renderengine/RenderEngine.h>
+
+#include <mutex>
+
+using namespace android;
+using namespace android::renderengine;
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers for Benchmark::Apply
+///////////////////////////////////////////////////////////////////////////////
+
+std::string RenderEngineTypeName(RenderEngine::RenderEngineType type) {
+ switch (type) {
+ case RenderEngine::RenderEngineType::SKIA_GL_THREADED:
+ return "skiaglthreaded";
+ case RenderEngine::RenderEngineType::SKIA_GL:
+ return "skiagl";
+ case RenderEngine::RenderEngineType::GLES:
+ case RenderEngine::RenderEngineType::THREADED:
+ LOG_ALWAYS_FATAL("GLESRenderEngine is deprecated - why time it?");
+ return "unused";
+ }
+}
+
+/**
+ * Passed (indirectly - see RunSkiaGL) to Benchmark::Apply to create a Benchmark
+ * which specifies which RenderEngineType it uses.
+ *
+ * This simplifies calling ->Arg(type)->Arg(type) and provides strings to make
+ * it obvious which version is being run.
+ *
+ * @param b The benchmark family
+ * @param type The type of RenderEngine to use.
+ */
+static void AddRenderEngineType(benchmark::internal::Benchmark* b,
+ RenderEngine::RenderEngineType type) {
+ b->Arg(static_cast<int64_t>(type));
+ b->ArgName(RenderEngineTypeName(type));
+}
+
+/**
+ * Run a benchmark once using SKIA_GL.
+ */
+static void RunSkiaGL(benchmark::internal::Benchmark* b) {
+ AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers for calling drawLayers
+///////////////////////////////////////////////////////////////////////////////
+
+std::pair<uint32_t, uint32_t> getDisplaySize() {
+ // These will be retrieved from a ui::Size, which stores int32_t, but they will be passed
+ // to GraphicBuffer, which wants uint32_t.
+ static uint32_t width, height;
+ std::once_flag once;
+ std::call_once(once, []() {
+ auto surfaceComposerClient = SurfaceComposerClient::getDefault();
+ auto displayToken = surfaceComposerClient->getInternalDisplayToken();
+ ui::DisplayMode displayMode;
+ if (surfaceComposerClient->getActiveDisplayMode(displayToken, &displayMode) < 0) {
+ LOG_ALWAYS_FATAL("Failed to get active display mode!");
+ }
+ auto w = displayMode.resolution.width;
+ auto h = displayMode.resolution.height;
+ LOG_ALWAYS_FATAL_IF(w <= 0 || h <= 0, "Invalid display size!");
+ width = static_cast<uint32_t>(w);
+ height = static_cast<uint32_t>(h);
+ });
+ return std::pair<uint32_t, uint32_t>(width, height);
+}
+
+// This value doesn't matter, as it's not read. TODO(b/199918329): Once we remove
+// GLESRenderEngine we can remove this, too.
+static constexpr const bool kUseFrameBufferCache = false;
+
+static std::unique_ptr<RenderEngine> createRenderEngine(RenderEngine::RenderEngineType type) {
+ auto args = RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(1)
+ .setEnableProtectedContext(true)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setSupportsBackgroundBlur(true)
+ .setContextPriority(RenderEngine::ContextPriority::REALTIME)
+ .setRenderEngineType(type)
+ .setUseColorManagerment(true)
+ .build();
+ return RenderEngine::create(args);
+}
+
+static std::shared_ptr<ExternalTexture> allocateBuffer(RenderEngine& re,
+ uint32_t width,
+ uint32_t height,
+ uint64_t extraUsageFlags = 0,
+ std::string name = "output") {
+ return std::make_shared<ExternalTexture>(new GraphicBuffer(width, height,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE |
+ extraUsageFlags,
+ std::move(name)),
+ re,
+ ExternalTexture::Usage::READABLE |
+ ExternalTexture::Usage::WRITEABLE);
+}
+
+static std::shared_ptr<ExternalTexture> copyBuffer(RenderEngine& re,
+ std::shared_ptr<ExternalTexture> original,
+ uint64_t extraUsageFlags, std::string name) {
+ const uint32_t width = original->getBuffer()->getWidth();
+ const uint32_t height = original->getBuffer()->getHeight();
+ auto texture = allocateBuffer(re, width, height, extraUsageFlags, name);
+
+ const Rect displayRect(0, 0, static_cast<int32_t>(width), static_cast<int32_t>(height));
+ DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .maxLuminance = 500,
+ };
+
+ const FloatRect layerRect(0, 0, width, height);
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .boundaries = layerRect,
+ },
+ .source =
+ PixelSource{
+ .buffer =
+ Buffer{
+ .buffer = original,
+ },
+ },
+ .alpha = half(1.0f),
+ };
+ auto layers = std::vector<LayerSettings>{layer};
+
+ auto [status, drawFence] =
+ re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd()).get();
+ sp<Fence> waitFence = new Fence(std::move(drawFence));
+ waitFence->waitForever(LOG_TAG);
+ return texture;
+}
+
+static void benchDrawLayers(RenderEngine& re, const std::vector<LayerSettings>& layers,
+ benchmark::State& benchState, const char* saveFileName) {
+ auto [width, height] = getDisplaySize();
+ auto outputBuffer = allocateBuffer(re, width, height);
+
+ const Rect displayRect(0, 0, static_cast<int32_t>(width), static_cast<int32_t>(height));
+ DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .maxLuminance = 500,
+ };
+
+ base::unique_fd fence;
+ for (auto _ : benchState) {
+ auto [status, drawFence] =
+ re.drawLayers(display, layers, outputBuffer, kUseFrameBufferCache, std::move(fence))
+ .get();
+ fence = std::move(drawFence);
+ }
+
+ if (renderenginebench::save() && saveFileName) {
+ sp<Fence> waitFence = new Fence(std::move(fence));
+ waitFence->waitForever(LOG_TAG);
+
+ // Copy to a CPU-accessible buffer so we can encode it.
+ outputBuffer = copyBuffer(re, outputBuffer, GRALLOC_USAGE_SW_READ_OFTEN, "to_encode");
+
+ std::string outFile = base::GetExecutableDirectory();
+ outFile.append("/");
+ outFile.append(saveFileName);
+ outFile.append(".jpg");
+ renderenginebench::encodeToJpeg(outFile.c_str(), outputBuffer->getBuffer());
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Benchmarks
+///////////////////////////////////////////////////////////////////////////////
+
+void BM_blur(benchmark::State& benchState) {
+ auto re = createRenderEngine(static_cast<RenderEngine::RenderEngineType>(benchState.range()));
+
+ // Initially use cpu access so we can decode into it with AImageDecoder.
+ auto [width, height] = getDisplaySize();
+ auto srcBuffer = allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ "decoded_source");
+ {
+ std::string srcImage = base::GetExecutableDirectory();
+ srcImage.append("/resources/homescreen.png");
+ renderenginebench::decode(srcImage.c_str(), srcBuffer->getBuffer());
+
+ // Now copy into GPU-only buffer for more realistic timing.
+ srcBuffer = copyBuffer(*re, srcBuffer, 0, "source");
+ }
+
+ const FloatRect layerRect(0, 0, width, height);
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .boundaries = layerRect,
+ },
+ .source =
+ PixelSource{
+ .buffer =
+ Buffer{
+ .buffer = srcBuffer,
+ },
+ },
+ .alpha = half(1.0f),
+ };
+ LayerSettings blurLayer{
+ .geometry =
+ Geometry{
+ .boundaries = layerRect,
+ },
+ .alpha = half(1.0f),
+ .skipContentDraw = true,
+ .backgroundBlurRadius = 60,
+ };
+
+ auto layers = std::vector<LayerSettings>{layer, blurLayer};
+ benchDrawLayers(*re, layers, benchState, "blurred");
+}
+
+BENCHMARK(BM_blur)->Apply(RunSkiaGL);
diff --git a/libs/renderengine/benchmark/RenderEngineBench.h b/libs/renderengine/benchmark/RenderEngineBench.h
new file mode 100644
index 0000000..1a25d77
--- /dev/null
+++ b/libs/renderengine/benchmark/RenderEngineBench.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#include <ui/GraphicBuffer.h>
+
+using namespace android;
+
+/**
+ * Utilities for running benchmarks.
+ */
+namespace renderenginebench {
+/**
+ * Parse RenderEngineBench-specific flags from the command line.
+ *
+ * --save Save the output buffer to a file to verify that it drew as
+ * expected.
+ */
+void parseFlags(int argc, char** argv);
+
+/**
+ * Parse flags for '--help'
+ */
+void parseFlagsForHelp(int argc, char** argv);
+
+/**
+ * Whether to save the drawing result to a file.
+ *
+ * True if --save was used on the command line.
+ */
+bool save();
+
+/**
+ * Decode the image at 'path' into 'buffer'.
+ *
+ * Currently only used for debugging. The image will be scaled to fit the
+ * buffer if necessary.
+ *
+ * This assumes the buffer matches ANDROID_BITMAP_FORMAT_RGBA_8888.
+ *
+ * @param path Relative to the directory holding the executable.
+ */
+void decode(const char* path, const sp<GraphicBuffer>& buffer);
+
+/**
+ * Encode the buffer to a jpeg.
+ *
+ * This assumes the buffer matches ANDROID_BITMAP_FORMAT_RGBA_8888.
+ *
+ * @param path Relative to the directory holding the executable.
+ */
+void encodeToJpeg(const char* path, const sp<GraphicBuffer>& buffer);
+} // namespace renderenginebench
diff --git a/libs/renderengine/benchmark/main.cpp b/libs/renderengine/benchmark/main.cpp
new file mode 100644
index 0000000..7a62853
--- /dev/null
+++ b/libs/renderengine/benchmark/main.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#include <RenderEngineBench.h>
+#include <benchmark/benchmark.h>
+
+int main(int argc, char** argv) {
+ // Initialize will exit if it sees '--help', so check for it and print info
+ // about our flags first.
+ renderenginebench::parseFlagsForHelp(argc, argv);
+ benchmark::Initialize(&argc, argv);
+
+ // Calling this separately from parseFlagsForHelp prevents collisions with
+ // google-benchmark's flags, since Initialize will consume and remove flags
+ // it recognizes.
+ renderenginebench::parseFlags(argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ return 0;
+}
diff --git a/libs/renderengine/benchmark/resources/homescreen.png b/libs/renderengine/benchmark/resources/homescreen.png
new file mode 100644
index 0000000..997b72d
--- /dev/null
+++ b/libs/renderengine/benchmark/resources/homescreen.png
Binary files differ
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index d5ec774..21d5603 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -53,6 +53,8 @@
#include "SkBlendMode.h"
#include "SkImageInfo.h"
#include "filters/BlurFilter.h"
+#include "filters/GaussianBlurFilter.h"
+#include "filters/KawaseBlurFilter.h"
#include "filters/LinearEffect.h"
#include "log/log_main.h"
#include "skia/debug/SkiaCapture.h"
@@ -328,7 +330,7 @@
if (args.supportsBackgroundBlur) {
ALOGD("Background Blurs Enabled");
- mBlurFilter = new BlurFilter();
+ mBlurFilter = new KawaseBlurFilter();
}
mCapture = std::make_unique<SkiaCapture>();
}
@@ -803,11 +805,11 @@
continue;
}
if (layer.backgroundBlurRadius > 0 &&
- layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) {
+ layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
requiresCompositionLayer = true;
}
for (auto region : layer.blurRegions) {
- if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) {
+ if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
requiresCompositionLayer = true;
}
}
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 2b6833e..6746e47 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 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.
@@ -15,7 +15,6 @@
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
#include "BlurFilter.h"
#include <SkCanvas.h>
#include <SkData.h>
@@ -32,33 +31,7 @@
namespace renderengine {
namespace skia {
-BlurFilter::BlurFilter() {
- SkString blurString(R"(
- uniform shader child;
- uniform float2 in_blurOffset;
- uniform float2 in_maxSizeXY;
-
- half4 main(float2 xy) {
- half4 c = child.eval(xy);
- c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
- clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
- c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
- clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
- c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
- clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
- c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
- clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
-
- return half4(c.rgb * 0.2, 1.0);
- }
- )");
-
- auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
- if (!blurEffect) {
- LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
- }
- mBlurEffect = std::move(blurEffect);
-
+static sk_sp<SkRuntimeEffect> createMixEffect() {
SkString mixString(R"(
uniform shader blurredInput;
uniform shader originalInput;
@@ -73,58 +46,12 @@
if (!mixEffect) {
LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str());
}
- mMixEffect = std::move(mixEffect);
+ return mixEffect;
}
-sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
- const sk_sp<SkImage> input, const SkRect& blurRect) const {
- // Kawase is an approximation of Gaussian, but it behaves differently from it.
- // A radius transformation is required for approximating them, and also to introduce
- // non-integer steps, necessary to smoothly interpolate large radii.
- float tmpRadius = (float)blurRadius / 2.0f;
- float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
- float radiusByPasses = tmpRadius / (float)numberOfPasses;
-
- // create blur surface with the bit depth and colorspace of the original surface
- SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale),
- std::ceil(blurRect.height() * kInputScale));
-
- const float stepX = radiusByPasses;
- const float stepY = radiusByPasses;
-
- // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
- // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale)
- // but instead we must do the inverse.
- SkMatrix blurMatrix = SkMatrix::Translate(-blurRect.fLeft, -blurRect.fTop);
- blurMatrix.postScale(kInputScale, kInputScale);
-
- // start by downscaling and doing the first blur pass
- SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
- SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
- blurBuilder.child("child") =
- input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
- blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale};
- blurBuilder.uniform("in_maxSizeXY") =
- SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale};
-
- sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
-
- // And now we'll build our chain of scaled blur stages
- for (auto i = 1; i < numberOfPasses; i++) {
- const float stepScale = (float)i * kInputScale;
- blurBuilder.child("child") =
- tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
- blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
- blurBuilder.uniform("in_maxSizeXY") =
- SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale};
- tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
- }
-
- return tmpBlur;
-}
-
-static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, float scale) {
- // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
+static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect,
+ const float scale) {
+ // 1. Apply the blur shader matrix, which scales up the blurred surface to its real size
auto matrix = SkMatrix::Scale(scale, scale);
// 2. Since the blurred surface has the size of the layer, we align it with the
// top left corner of the layer position.
@@ -139,6 +66,14 @@
return matrix;
}
+BlurFilter::BlurFilter(const float maxCrossFadeRadius)
+ : mMaxCrossFadeRadius(maxCrossFadeRadius),
+ mMixEffect(maxCrossFadeRadius > 0 ? createMixEffect() : nullptr) {}
+
+float BlurFilter::getMaxCrossFadeRadius() const {
+ return mMaxCrossFadeRadius;
+}
+
void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion,
const uint32_t blurRadius, const float blurAlpha,
const SkRect& blurRect, sk_sp<SkImage> blurredImage,
@@ -153,7 +88,7 @@
const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
linearSampling, &blurMatrix);
- if (blurRadius < kMaxCrossFadeRadius) {
+ if (blurRadius < mMaxCrossFadeRadius) {
// For sampling Skia's API expects the inverse of what logically seems appropriate. In this
// case you might expect the matrix to simply be the canvas matrix.
SkMatrix inputMatrix;
@@ -166,7 +101,7 @@
blurBuilder.child("originalInput") =
input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
inputMatrix);
- blurBuilder.uniform("mixFactor") = blurRadius / kMaxCrossFadeRadius;
+ blurBuilder.uniform("mixFactor") = blurRadius / mMaxCrossFadeRadius;
paint.setShader(blurBuilder.makeShader(nullptr, true));
} else {
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 7110018..9cddc75 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -27,29 +27,19 @@
namespace renderengine {
namespace skia {
-/**
- * This is an implementation of a Kawase blur, as described in here:
- * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/
- * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf
- */
class BlurFilter {
public:
// Downsample FBO to improve performance
static constexpr float kInputScale = 0.25f;
// Downsample scale factor used to improve performance
static constexpr float kInverseInputScale = 1.0f / kInputScale;
- // Maximum number of render passes
- static constexpr uint32_t kMaxPasses = 4;
- // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
- // image, up to this radius.
- static constexpr float kMaxCrossFadeRadius = 10.0f;
- explicit BlurFilter();
- virtual ~BlurFilter(){};
+ explicit BlurFilter(float maxCrossFadeRadius = 10.0f);
+ virtual ~BlurFilter(){}
// Execute blur, saving it to a texture
- sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
- const sk_sp<SkImage> blurInput, const SkRect& blurRect) const;
+ virtual sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
+ const sk_sp<SkImage> blurInput, const SkRect& blurRect) const = 0;
/**
* Draw the blurred content (from the generate method) into the canvas.
@@ -61,13 +51,20 @@
* @param blurredImage down-sampled blurred content that was produced by the generate() method
* @param input original unblurred input that is used to crossfade with the blurredImage
*/
- void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius,
- const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage,
- sk_sp<SkImage> input);
+ void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion,
+ const uint32_t blurRadius, const float blurAlpha,
+ const SkRect& blurRect, sk_sp<SkImage> blurredImage,
+ sk_sp<SkImage> input);
+
+ float getMaxCrossFadeRadius() const;
private:
- sk_sp<SkRuntimeEffect> mBlurEffect;
- sk_sp<SkRuntimeEffect> mMixEffect;
+ // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
+ // image, up to this radius.
+ const float mMaxCrossFadeRadius;
+
+ // Optional blend used for crossfade only if mMaxCrossFadeRadius > 0
+ const sk_sp<SkRuntimeEffect> mMixEffect;
};
} // namespace skia
diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp
new file mode 100644
index 0000000..55867a9
--- /dev/null
+++ b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GaussianBlurFilter.h"
+#include <SkCanvas.h>
+#include <SkData.h>
+#include <SkPaint.h>
+#include <SkRRect.h>
+#include <SkRuntimeEffect.h>
+#include <SkImageFilters.h>
+#include <SkSize.h>
+#include <SkString.h>
+#include <SkSurface.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+// This constant approximates the scaling done in the software path's
+// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
+static const float BLUR_SIGMA_SCALE = 0.57735f;
+
+GaussianBlurFilter::GaussianBlurFilter(): BlurFilter(/* maxCrossFadeRadius= */ 0.0f) {}
+
+sk_sp<SkImage> GaussianBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
+ const sk_sp<SkImage> input, const SkRect& blurRect)
+ const {
+ // Create blur surface with the bit depth and colorspace of the original surface
+ SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale),
+ std::ceil(blurRect.height() * kInputScale));
+ sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, scaledInfo);
+
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ paint.setImageFilter(SkImageFilters::Blur(
+ blurRadius * kInputScale * BLUR_SIGMA_SCALE,
+ blurRadius * kInputScale * BLUR_SIGMA_SCALE,
+ SkTileMode::kClamp, nullptr));
+
+ surface->getCanvas()->drawImageRect(
+ input,
+ blurRect,
+ SkRect::MakeWH(scaledInfo.width(), scaledInfo.height()),
+ SkSamplingOptions{SkFilterMode::kLinear, SkMipmapMode::kNone},
+ &paint,
+ SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint);
+ return surface->makeImageSnapshot();
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.h b/libs/renderengine/skia/filters/GaussianBlurFilter.h
new file mode 100644
index 0000000..a4febd2
--- /dev/null
+++ b/libs/renderengine/skia/filters/GaussianBlurFilter.h
@@ -0,0 +1,47 @@
+/*
+ * 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 "BlurFilter.h"
+#include <SkCanvas.h>
+#include <SkImage.h>
+#include <SkRuntimeEffect.h>
+#include <SkSurface.h>
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+/**
+ * This is an implementation of a Gaussian blur using Skia's built-in GaussianBlur filter.
+ */
+class GaussianBlurFilter: public BlurFilter {
+public:
+ explicit GaussianBlurFilter();
+ virtual ~GaussianBlurFilter(){}
+
+ // Execute blur, saving it to a texture
+ sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
+ const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override;
+
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
new file mode 100644
index 0000000..bfde06f
--- /dev/null
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "KawaseBlurFilter.h"
+#include <SkCanvas.h>
+#include <SkData.h>
+#include <SkPaint.h>
+#include <SkRRect.h>
+#include <SkRuntimeEffect.h>
+#include <SkSize.h>
+#include <SkString.h>
+#include <SkSurface.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() {
+ SkString blurString(R"(
+ uniform shader child;
+ uniform float in_blurOffset;
+
+ half4 main(float2 xy) {
+ half4 c = child.eval(xy);
+ c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset));
+ c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset));
+ c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset));
+ c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset));
+ return half4(c.rgb * 0.2, 1.0);
+ }
+ )");
+
+ auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
+ if (!blurEffect) {
+ LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
+ }
+ mBlurEffect = std::move(blurEffect);
+}
+
+sk_sp<SkImage> KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
+ const sk_sp<SkImage> input, const SkRect& blurRect)
+ const {
+ // Kawase is an approximation of Gaussian, but it behaves differently from it.
+ // A radius transformation is required for approximating them, and also to introduce
+ // non-integer steps, necessary to smoothly interpolate large radii.
+ float tmpRadius = (float)blurRadius / 2.0f;
+ float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
+ float radiusByPasses = tmpRadius / (float)numberOfPasses;
+
+ // create blur surface with the bit depth and colorspace of the original surface
+ SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale),
+ std::ceil(blurRect.height() * kInputScale));
+
+ // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
+ // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale)
+ // but instead we must do the inverse.
+ SkMatrix blurMatrix = SkMatrix::Translate(-blurRect.fLeft, -blurRect.fTop);
+ blurMatrix.postScale(kInputScale, kInputScale);
+
+ // start by downscaling and doing the first blur pass
+ SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
+ SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
+ blurBuilder.child("child") =
+ input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
+ blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale;
+
+ sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
+
+ // And now we'll build our chain of scaled blur stages
+ for (auto i = 1; i < numberOfPasses; i++) {
+ blurBuilder.child("child") =
+ tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
+ blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale;
+ tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
+ }
+
+ return tmpBlur;
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.h b/libs/renderengine/skia/filters/KawaseBlurFilter.h
new file mode 100644
index 0000000..0ac5ac8
--- /dev/null
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.h
@@ -0,0 +1,54 @@
+/*
+ * 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 "BlurFilter.h"
+#include <SkCanvas.h>
+#include <SkImage.h>
+#include <SkRuntimeEffect.h>
+#include <SkSurface.h>
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+/**
+ * This is an implementation of a Kawase blur, as described in here:
+ * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/
+ * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf
+ */
+class KawaseBlurFilter: public BlurFilter {
+public:
+ // Maximum number of render passes
+ static constexpr uint32_t kMaxPasses = 4;
+
+ explicit KawaseBlurFilter();
+ virtual ~KawaseBlurFilter(){}
+
+ // Execute blur, saving it to a texture
+ sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
+ const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override;
+
+private:
+ sk_sp<SkRuntimeEffect> mBlurEffect;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index 7634007..9aae145 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -124,7 +124,7 @@
// getStatus() returns whether the fence has signaled yet. Prefer this to
// getSignalTime() or wait() if all you care about is whether the fence has
// signaled.
- inline Status getStatus() {
+ virtual inline Status getStatus() {
// The sync_wait call underlying wait() has been measured to be
// significantly faster than the sync_fence_info call underlying
// getSignalTime(), which might otherwise appear to be the more obvious
diff --git a/libs/ui/include_mock/ui/MockFence.h b/libs/ui/include_mock/ui/MockFence.h
index 162ec02..71adee4 100644
--- a/libs/ui/include_mock/ui/MockFence.h
+++ b/libs/ui/include_mock/ui/MockFence.h
@@ -27,6 +27,7 @@
virtual ~MockFence() = default;
MOCK_METHOD(nsecs_t, getSignalTime, (), (const, override));
+ MOCK_METHOD(Status, getStatus, (), (override));
};
}; // namespace android::mock
diff --git a/libs/ui/tests/MockFence_test.cpp b/libs/ui/tests/MockFence_test.cpp
index 6e520b1..40dddc3 100644
--- a/libs/ui/tests/MockFence_test.cpp
+++ b/libs/ui/tests/MockFence_test.cpp
@@ -42,4 +42,16 @@
EXPECT_EQ(1234, fence->getSignalTime());
}
+TEST_F(MockFenceTest, getStatus) {
+ sp<Fence> fence = getFenceForTesting();
+
+ EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Unsignaled));
+ EXPECT_EQ(Fence::Status::Unsignaled, fence->getStatus());
+
+ EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Signaled));
+ EXPECT_EQ(Fence::Status::Signaled, fence->getStatus());
+
+ EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Invalid));
+ EXPECT_EQ(Fence::Status::Invalid, fence->getStatus());
+}
} // namespace android::ui
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
deleted file mode 100644
index bf848af..0000000
--- a/libs/vr/libvrflinger/Android.bp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (C) 2008 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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sourceFiles = [
- "acquired_buffer.cpp",
- "epoll_event_dispatcher.cpp",
- "display_manager_service.cpp",
- "display_service.cpp",
- "display_surface.cpp",
- "hardware_composer.cpp",
- "vr_flinger.cpp",
-]
-
-includeFiles = [ "include" ]
-
-staticLibraries = [
- "libdisplay",
- "libdvrcommon",
- "libperformance",
- "libvrsensor",
- "libbroadcastring",
- "libvr_manager",
- "libbroadcastring",
-]
-
-sharedLibraries = [
- "android.frameworks.vr.composer@2.0",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.composer@2.2",
- "android.hardware.graphics.composer@2.3",
- "android.hardware.graphics.composer@2.4",
- "libbinder",
- "libbase",
- "libbufferhubqueue",
- "libcutils",
- "liblog",
- "libhardware",
- "libnativewindow",
- "libprocessgroup",
- "libutils",
- "libEGL",
- "libGLESv1_CM",
- "libGLESv2",
- "libvulkan",
- "libui",
- "libgui",
- "libsync",
- "libhidlbase",
- "libfmq",
- "libpdx_default_transport",
-]
-
-headerLibraries = [
- "android.hardware.graphics.composer@2.1-command-buffer",
- "android.hardware.graphics.composer@2.2-command-buffer",
- "android.hardware.graphics.composer@2.3-command-buffer",
- "android.hardware.graphics.composer@2.4-command-buffer",
- "libdvr_headers",
- "libsurfaceflinger_headers",
-]
-
-cc_library_static {
- srcs: sourceFiles,
- export_include_dirs: includeFiles,
-
- clang: true,
- cflags: [
- "-DLOG_TAG=\"vr_flinger\"",
- "-DTRACE=0",
- "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
- "-DGL_GLEXT_PROTOTYPES",
- "-DEGL_EGLEXT_PROTOTYPES",
- "-Wall",
- "-Werror",
- "-Wno-error=sign-compare", // to fix later
- "-Wno-unused-variable",
- ],
- shared_libs: sharedLibraries,
- whole_static_libs: staticLibraries,
- header_libs: headerLibraries,
- name: "libvrflinger",
-}
-
-subdirs = [
- "tests",
-]
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
deleted file mode 100644
index c360dee..0000000
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "acquired_buffer.h"
-
-#include <log/log.h>
-#include <sync/sync.h>
-
-using android::pdx::LocalHandle;
-
-namespace android {
-namespace dvr {
-
-AcquiredBuffer::AcquiredBuffer(const std::shared_ptr<ConsumerBuffer>& buffer,
- LocalHandle acquire_fence, std::size_t slot)
- : buffer_(buffer), acquire_fence_(std::move(acquire_fence)), slot_(slot) {}
-
-AcquiredBuffer::AcquiredBuffer(const std::shared_ptr<ConsumerBuffer>& buffer,
- int* error) {
- LocalHandle fence;
- const int ret = buffer->Acquire(&fence);
-
- if (error)
- *error = ret;
-
- if (ret < 0) {
- ALOGW("AcquiredBuffer::AcquiredBuffer: Failed to acquire buffer: %s",
- strerror(-ret));
- buffer_ = nullptr;
- // Default construct sets acquire_fence_ to empty.
- } else {
- buffer_ = buffer;
- acquire_fence_ = std::move(fence);
- }
-}
-
-AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) noexcept {
- *this = std::move(other);
-}
-
-AcquiredBuffer::~AcquiredBuffer() { Release(LocalHandle(kEmptyFence)); }
-
-AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) noexcept {
- if (this != &other) {
- Release();
-
- using std::swap;
- swap(buffer_, other.buffer_);
- swap(acquire_fence_, other.acquire_fence_);
- swap(slot_, other.slot_);
- }
- return *this;
-}
-
-bool AcquiredBuffer::IsAvailable() const {
- if (IsEmpty())
- return false;
-
- // Only check the fence if the acquire fence is not empty.
- if (acquire_fence_) {
- const int ret = sync_wait(acquire_fence_.Get(), 0);
- ALOGD_IF(TRACE || (ret < 0 && errno != ETIME),
- "AcquiredBuffer::IsAvailable: buffer_id=%d acquire_fence=%d "
- "sync_wait()=%d errno=%d.",
- buffer_->id(), acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
- if (ret == 0) {
- // The fence is completed, so to avoid further calls to sync_wait we close
- // it here.
- acquire_fence_.Close();
- }
- return ret == 0;
- } else {
- return true;
- }
-}
-
-LocalHandle AcquiredBuffer::ClaimAcquireFence() {
- return std::move(acquire_fence_);
-}
-
-std::shared_ptr<ConsumerBuffer> AcquiredBuffer::ClaimBuffer() {
- return std::move(buffer_);
-}
-
-int AcquiredBuffer::Release(LocalHandle release_fence) {
- ALOGD_IF(TRACE, "AcquiredBuffer::Release: buffer_id=%d release_fence=%d",
- buffer_ ? buffer_->id() : -1, release_fence.Get());
- if (buffer_) {
- const int ret = buffer_->ReleaseAsync();
- if (ret < 0) {
- ALOGE("AcquiredBuffer::Release: Failed to release buffer %d: %s",
- buffer_->id(), strerror(-ret));
- if (ret != -ESHUTDOWN)
- return ret;
- }
-
- buffer_ = nullptr;
- }
-
- acquire_fence_.Close();
- slot_ = 0;
- return 0;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
deleted file mode 100644
index 7643e75..0000000
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_DISPLAYD_ACQUIRED_BUFFER_H_
-#define ANDROID_DVR_SERVICES_DISPLAYD_ACQUIRED_BUFFER_H_
-
-#include <pdx/file_handle.h>
-#include <private/dvr/consumer_buffer.h>
-
-#include <memory>
-
-namespace android {
-namespace dvr {
-
-// Manages the ACQUIRE/RELEASE ownership cycle of a ConsumerBuffer.
-class AcquiredBuffer {
- public:
- static constexpr int kEmptyFence = pdx::LocalHandle::kEmptyFileHandle;
-
- AcquiredBuffer() : buffer_(nullptr), acquire_fence_(kEmptyFence) {}
-
- // Constructs an AcquiredBuffer from a ConsumerBuffer pointer and an acquire
- // fence. The ConsumerBuffer MUST be in the ACQUIRED state prior to calling
- // this constructor; the constructor does not attempt to ACQUIRE the buffer
- // itself.
- AcquiredBuffer(const std::shared_ptr<ConsumerBuffer>& buffer,
- pdx::LocalHandle acquire_fence, std::size_t slot = 0);
-
- // Constructs an AcquiredBuffer from a ConsumerBuffer. The ConsumerBuffer MUST
- // be in the POSTED state prior to calling this constructor, as this
- // constructor attempts to ACQUIRE the buffer. If ACQUIRING the buffer fails
- // this instance is left in the empty state. An optional error code is
- // returned in |error|, which may be nullptr if not needed.
- AcquiredBuffer(const std::shared_ptr<ConsumerBuffer>& buffer, int* error);
-
- // Move constructor. Behaves similarly to the move assignment operator below.
- AcquiredBuffer(AcquiredBuffer&& other) noexcept;
-
- ~AcquiredBuffer();
-
- // Move assignment operator. Moves the ConsumerBuffer and acquire fence from
- // |other| into this instance after RELEASING the current ConsumerBuffer and
- // closing the acquire fence. After the move |other| is left in the empty
- // state.
- AcquiredBuffer& operator=(AcquiredBuffer&& other) noexcept;
-
- // Accessors for the underlying ConsumerBuffer, the acquire fence, and the
- // use-case specific sequence value from the acquisition (see
- // private/dvr/consumer_buffer.h).
- std::shared_ptr<ConsumerBuffer> buffer() const { return buffer_; }
- int acquire_fence() const { return acquire_fence_.Get(); }
-
- // When non-empty, returns true if the acquired fence was signaled (or if the
- // fence is empty). Returns false when empty or if the fence is not signaled.
- bool IsAvailable() const;
-
- bool IsEmpty() const { return buffer_ == nullptr; }
-
- // Returns the acquire fence, passing ownership to the caller.
- pdx::LocalHandle ClaimAcquireFence();
-
- // Returns the buffer, passing ownership to the caller. Caller is responsible
- // for calling Release on the returned buffer.
- std::shared_ptr<ConsumerBuffer> ClaimBuffer();
-
- // Releases the ConsumerBuffer, passing the release fence in |release_fence|
- // to the producer. On success, the ConsumerBuffer and acquire fence are set
- // to empty state; if release fails, the ConsumerBuffer and acquire fence are
- // left in place and a negative error code is returned.
- int Release(pdx::LocalHandle release_fence = {});
-
- // Returns the slot in the queue this buffer belongs to. Buffers that are not
- // part of a queue return 0.
- std::size_t slot() const { return slot_; }
-
- private:
- std::shared_ptr<ConsumerBuffer> buffer_;
- // Mutable so that the fence can be closed when it is determined to be
- // signaled during IsAvailable().
- mutable pdx::LocalHandle acquire_fence_;
- std::size_t slot_{0};
-
- AcquiredBuffer(const AcquiredBuffer&) = delete;
- void operator=(const AcquiredBuffer&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_SERVICES_DISPLAYD_ACQUIRED_BUFFER_H_
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
deleted file mode 100644
index 34b3b0a..0000000
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-#include "display_manager_service.h"
-
-#include <pdx/channel_handle.h>
-#include <pdx/default_transport/service_endpoint.h>
-#include <private/android_filesystem_config.h>
-#include <private/dvr/display_protocol.h>
-#include <private/dvr/trusted_uids.h>
-#include <sys/poll.h>
-
-#include <array>
-
-using android::dvr::display::DisplayManagerProtocol;
-using android::pdx::Channel;
-using android::pdx::LocalChannelHandle;
-using android::pdx::Message;
-using android::pdx::default_transport::Endpoint;
-using android::pdx::ErrorStatus;
-using android::pdx::rpc::DispatchRemoteMethod;
-using android::pdx::rpc::IfAnyOf;
-using android::pdx::rpc::RemoteMethodError;
-
-namespace android {
-namespace dvr {
-
-void DisplayManager::SetNotificationsPending(bool pending) {
- auto status = service_->ModifyChannelEvents(channel_id_, pending ? 0 : POLLIN,
- pending ? POLLIN : 0);
- ALOGE_IF(!status,
- "DisplayManager::SetNotificationPending: Failed to modify channel "
- "events: %s",
- status.GetErrorMessage().c_str());
-}
-
-DisplayManagerService::DisplayManagerService(
- const std::shared_ptr<DisplayService>& display_service)
- : BASE("DisplayManagerService",
- Endpoint::Create(DisplayManagerProtocol::kClientPath)),
- display_service_(display_service) {
- display_service_->SetDisplayConfigurationUpdateNotifier(
- std::bind(&DisplayManagerService::OnDisplaySurfaceChange, this));
-}
-
-std::shared_ptr<pdx::Channel> DisplayManagerService::OnChannelOpen(
- pdx::Message& message) {
- const int user_id = message.GetEffectiveUserId();
- const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
-
- // Check if the display_manager_ has a defunct channel.
- if (display_manager_ && !HasChannelId(display_manager_->channel_id())) {
- ALOGE("DisplayManagerService::OnChannelOpen: Found defunct channel %d with "
- "no OnChannelClose, clearing prior display manager.",
- display_manager_->channel_id());
- display_manager_ = nullptr;
- }
-
- // Prevent more than one display manager from registering at a time or
- // untrusted UIDs from connecting.
- if (display_manager_ || !trusted) {
- RemoteMethodError(message, EPERM);
- return nullptr;
- }
-
- display_manager_ =
- std::make_shared<DisplayManager>(this, message.GetChannelId());
- return display_manager_;
-}
-
-void DisplayManagerService::OnChannelClose(
- pdx::Message& /*message*/, const std::shared_ptr<pdx::Channel>& channel) {
- // Unregister the display manager when the channel closes.
- if (display_manager_ == channel)
- display_manager_ = nullptr;
-}
-
-pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) {
- ATRACE_NAME("DisplayManagerService::HandleMessage");
- auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());
-
- switch (message.GetOp()) {
- case DisplayManagerProtocol::GetSurfaceState::Opcode:
- DispatchRemoteMethod<DisplayManagerProtocol::GetSurfaceState>(
- *this, &DisplayManagerService::OnGetSurfaceState, message);
- return {};
-
- case DisplayManagerProtocol::GetSurfaceQueue::Opcode:
- DispatchRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>(
- *this, &DisplayManagerService::OnGetSurfaceQueue, message);
- return {};
-
- default:
- return Service::DefaultHandleMessage(message);
- }
-}
-
-pdx::Status<std::vector<display::SurfaceState>>
-DisplayManagerService::OnGetSurfaceState(pdx::Message& /*message*/) {
- std::vector<display::SurfaceState> items;
-
- display_service_->ForEachDisplaySurface(
- SurfaceType::Application,
- [&items](const std::shared_ptr<DisplaySurface>& surface) mutable {
- items.push_back({surface->surface_id(), surface->process_id(),
- surface->user_id(), surface->attributes(),
- surface->update_flags(), surface->GetQueueIds()});
- surface->ClearUpdate();
- });
-
- // The fact that we're in the message handler implies that display_manager_ is
- // not nullptr. No check required, unless this service becomes multi-threaded.
- display_manager_->SetNotificationsPending(false);
- return items;
-}
-
-pdx::Status<pdx::LocalChannelHandle> DisplayManagerService::OnGetSurfaceQueue(
- pdx::Message& /*message*/, int surface_id, int queue_id) {
- auto surface = display_service_->GetDisplaySurface(surface_id);
- if (!surface || surface->surface_type() != SurfaceType::Application)
- return ErrorStatus(EINVAL);
-
- auto queue =
- std::static_pointer_cast<ApplicationDisplaySurface>(surface)->GetQueue(
- queue_id);
- if (!queue)
- return ErrorStatus(EINVAL);
-
- auto status = queue->CreateConsumerQueueHandle();
- ALOGE_IF(
- !status,
- "DisplayManagerService::OnGetSurfaceQueue: Failed to create consumer "
- "queue for queue_id=%d: %s",
- queue->id(), status.GetErrorMessage().c_str());
-
- return status;
-}
-
-void DisplayManagerService::OnDisplaySurfaceChange() {
- if (display_manager_)
- display_manager_->SetNotificationsPending(true);
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
deleted file mode 100644
index 3133fe1..0000000
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_VRFLINGER_DISPLAY_MANAGER_SERVICE_H_
-#define ANDROID_DVR_SERVICES_VRFLINGER_DISPLAY_MANAGER_SERVICE_H_
-
-#include <pdx/service.h>
-#include <pdx/status.h>
-#include <private/dvr/display_protocol.h>
-
-#include "display_service.h"
-
-namespace android {
-namespace dvr {
-
-class DisplayManagerService;
-
-// The display manager is a client of the display manager service. This class
-// represents the connected client that the display manager service sends
-// notifications to.
-class DisplayManager : public pdx::Channel {
- public:
- DisplayManager(DisplayManagerService* service, int channel_id)
- : service_(service), channel_id_(channel_id) {}
-
- int channel_id() const { return channel_id_; }
-
- // Sets or clears the channel event mask to indicate pending events that the
- // display manager on the other end of the channel should read and handle.
- // When |pending| is true the POLLIN bit is set in the event mask; when
- // |pending| is false the POLLIN bit is cleared in the event mask.
- void SetNotificationsPending(bool pending);
-
- private:
- DisplayManager(const DisplayManager&) = delete;
- void operator=(const DisplayManager&) = delete;
-
- DisplayManagerService* service_;
- int channel_id_;
-};
-
-// The display manager service marshalls state and events from the display
-// service to the display manager.
-class DisplayManagerService : public pdx::ServiceBase<DisplayManagerService> {
- public:
- std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& message) override;
- void OnChannelClose(pdx::Message& message,
- const std::shared_ptr<pdx::Channel>& channel) override;
- pdx::Status<void> HandleMessage(pdx::Message& message) override;
-
- private:
- friend BASE;
-
- explicit DisplayManagerService(
- const std::shared_ptr<DisplayService>& display_service);
-
- pdx::Status<std::vector<display::SurfaceState>> OnGetSurfaceState(
- pdx::Message& message);
- pdx::Status<pdx::LocalChannelHandle> OnGetSurfaceQueue(pdx::Message& message,
- int surface_id,
- int queue_id);
-
- // Called by the display service to indicate changes to display surfaces that
- // the display manager should evaluate.
- void OnDisplaySurfaceChange();
-
- DisplayManagerService(const DisplayManagerService&) = delete;
- void operator=(const DisplayManagerService&) = delete;
-
- std::shared_ptr<DisplayService> display_service_;
- std::shared_ptr<DisplayManager> display_manager_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_SERVICES_VRFLINGER_DISPLAY_MANAGER_SERVICE_H_
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
deleted file mode 100644
index 582fed3..0000000
--- a/libs/vr/libvrflinger/display_service.cpp
+++ /dev/null
@@ -1,437 +0,0 @@
-#include "display_service.h"
-
-#include <unistd.h>
-
-#include <algorithm>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-#include <dvr/dvr_display_types.h>
-#include <pdx/default_transport/service_endpoint.h>
-#include <pdx/rpc/remote_method.h>
-#include <private/android_filesystem_config.h>
-#include <private/dvr/display_protocol.h>
-#include <private/dvr/numeric.h>
-#include <private/dvr/trusted_uids.h>
-#include <private/dvr/types.h>
-
-#include "DisplayHardware/DisplayIdentification.h"
-
-using android::dvr::display::DisplayProtocol;
-using android::pdx::Channel;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::Status;
-using android::pdx::default_transport::Endpoint;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace {
-
-const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
-const char kDvrDeviceMetricsProperty[] = "ro.dvr.device_metrics";
-const char kDvrDeviceConfigProperty[] = "ro.dvr.device_configuration";
-
-} // namespace
-
-namespace android {
-namespace dvr {
-
-DisplayService::DisplayService(Hwc2::Composer* hidl,
- hwc2_display_t primary_display_id,
- RequestDisplayCallback request_display_callback)
- : BASE("DisplayService",
- Endpoint::Create(display::DisplayProtocol::kClientPath)) {
- hardware_composer_.Initialize(
- hidl, primary_display_id, request_display_callback);
-}
-
-bool DisplayService::IsInitialized() const {
- return BASE::IsInitialized() && hardware_composer_.IsInitialized();
-}
-
-std::string DisplayService::DumpState(size_t /*max_length*/) {
- std::ostringstream stream;
-
- auto surfaces = GetDisplaySurfaces();
- std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
- return a->surface_id() < b->surface_id();
- });
-
- stream << "Application Surfaces:" << std::endl;
-
- size_t count = 0;
- for (const auto& surface : surfaces) {
- if (surface->surface_type() == SurfaceType::Application) {
- stream << "Surface " << count++ << ":";
- stream << " surface_id=" << surface->surface_id()
- << " process_id=" << surface->process_id()
- << " user_id=" << surface->user_id()
- << " visible=" << surface->visible()
- << " z_order=" << surface->z_order();
-
- stream << " queue_ids=";
- auto queue_ids = surface->GetQueueIds();
- std::sort(queue_ids.begin(), queue_ids.end());
- for (int32_t id : queue_ids) {
- if (id != queue_ids[0])
- stream << ",";
- stream << id;
- }
- stream << std::endl;
- }
- }
- stream << std::endl;
-
- stream << "Direct Surfaces:" << std::endl;
-
- count = 0;
- for (const auto& surface : surfaces) {
- if (surface->surface_type() == SurfaceType::Direct) {
- stream << "Surface " << count++ << ":";
- stream << " surface_id=" << surface->surface_id()
- << " process_id=" << surface->process_id()
- << " user_id=" << surface->user_id()
- << " visible=" << surface->visible()
- << " z_order=" << surface->z_order();
-
- stream << " queue_ids=";
- auto queue_ids = surface->GetQueueIds();
- std::sort(queue_ids.begin(), queue_ids.end());
- for (int32_t id : queue_ids) {
- if (id != queue_ids[0])
- stream << ",";
- stream << id;
- }
- stream << std::endl;
- }
- }
- stream << std::endl;
-
- stream << hardware_composer_.Dump();
- return stream.str();
-}
-
-void DisplayService::OnChannelClose(pdx::Message& message,
- const std::shared_ptr<Channel>& channel) {
- if (auto surface = std::static_pointer_cast<DisplaySurface>(channel)) {
- surface->OnSetAttributes(message,
- {{display::SurfaceAttribute::Visible,
- display::SurfaceAttributeValue{false}}});
- }
-}
-
-// First-level dispatch for display service messages. Directly handles messages
-// that are independent of the display surface (metrics, creation) and routes
-// surface-specific messages to the per-instance handlers.
-Status<void> DisplayService::HandleMessage(pdx::Message& message) {
- ALOGD_IF(TRACE, "DisplayService::HandleMessage: opcode=%d", message.GetOp());
- ATRACE_NAME("DisplayService::HandleMessage");
-
- switch (message.GetOp()) {
- case DisplayProtocol::GetMetrics::Opcode:
- DispatchRemoteMethod<DisplayProtocol::GetMetrics>(
- *this, &DisplayService::OnGetMetrics, message);
- return {};
-
- case DisplayProtocol::GetConfigurationData::Opcode:
- DispatchRemoteMethod<DisplayProtocol::GetConfigurationData>(
- *this, &DisplayService::OnGetConfigurationData, message);
- return {};
-
- case DisplayProtocol::GetDisplayIdentificationPort::Opcode:
- DispatchRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>(
- *this, &DisplayService::OnGetDisplayIdentificationPort, message);
- return {};
-
- case DisplayProtocol::CreateSurface::Opcode:
- DispatchRemoteMethod<DisplayProtocol::CreateSurface>(
- *this, &DisplayService::OnCreateSurface, message);
- return {};
-
- case DisplayProtocol::SetupGlobalBuffer::Opcode:
- DispatchRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(
- *this, &DisplayService::OnSetupGlobalBuffer, message);
- return {};
-
- case DisplayProtocol::DeleteGlobalBuffer::Opcode:
- DispatchRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(
- *this, &DisplayService::OnDeleteGlobalBuffer, message);
- return {};
-
- case DisplayProtocol::GetGlobalBuffer::Opcode:
- DispatchRemoteMethod<DisplayProtocol::GetGlobalBuffer>(
- *this, &DisplayService::OnGetGlobalBuffer, message);
- return {};
-
- case DisplayProtocol::IsVrAppRunning::Opcode:
- DispatchRemoteMethod<DisplayProtocol::IsVrAppRunning>(
- *this, &DisplayService::IsVrAppRunning, message);
- return {};
-
- // Direct the surface specific messages to the surface instance.
- case DisplayProtocol::SetAttributes::Opcode:
- case DisplayProtocol::CreateQueue::Opcode:
- case DisplayProtocol::GetSurfaceInfo::Opcode:
- return HandleSurfaceMessage(message);
-
- default:
- return Service::HandleMessage(message);
- }
-}
-
-Status<display::Metrics> DisplayService::OnGetMetrics(
- pdx::Message& /*message*/) {
- const auto& params = hardware_composer_.GetPrimaryDisplayParams();
- return {{static_cast<uint32_t>(params.width),
- static_cast<uint32_t>(params.height),
- static_cast<uint32_t>(params.dpi.x),
- static_cast<uint32_t>(params.dpi.y),
- static_cast<uint32_t>(params.vsync_period_ns),
- 0,
- 0,
- 0,
- 0.0,
- {},
- {}}};
-}
-
-pdx::Status<std::string> DisplayService::OnGetConfigurationData(
- pdx::Message& /*message*/, display::ConfigFileType config_type) {
- std::string property_name;
- DisplayIdentificationData display_identification_data;
- switch (config_type) {
- case display::ConfigFileType::kLensMetrics:
- property_name = kDvrLensMetricsProperty;
- break;
- case display::ConfigFileType::kDeviceMetrics:
- property_name = kDvrDeviceMetricsProperty;
- break;
- case display::ConfigFileType::kDeviceConfiguration:
- property_name = kDvrDeviceConfigProperty;
- break;
- case display::ConfigFileType::kDeviceEdid:
- display_identification_data =
- hardware_composer_.GetCurrentDisplayIdentificationData();
- if (display_identification_data.size() == 0) {
- return ErrorStatus(ENOENT);
- }
- return std::string(display_identification_data.begin(),
- display_identification_data.end());
- default:
- return ErrorStatus(EINVAL);
- }
- std::string file_path = base::GetProperty(property_name, "");
- if (file_path.empty()) {
- return ErrorStatus(ENOENT);
- }
-
- std::string data;
- if (!base::ReadFileToString(file_path, &data)) {
- return ErrorStatus(errno);
- }
-
- return std::move(data);
-}
-
-pdx::Status<uint8_t> DisplayService::OnGetDisplayIdentificationPort(
- pdx::Message& /*message*/) {
- return hardware_composer_.GetCurrentDisplayPort();
-}
-
-// Creates a new DisplaySurface and associates it with this channel. This may
-// only be done once per channel.
-Status<display::SurfaceInfo> DisplayService::OnCreateSurface(
- pdx::Message& message, const display::SurfaceAttributes& attributes) {
- // A surface may only be created once per channel.
- if (message.GetChannel())
- return ErrorStatus(EINVAL);
-
- ALOGI_IF(TRACE, "DisplayService::OnCreateSurface: cid=%d",
- message.GetChannelId());
-
- // Use the channel id as the unique surface id.
- const int surface_id = message.GetChannelId();
- const int process_id = message.GetProcessId();
- const int user_id = message.GetEffectiveUserId();
-
- ALOGI_IF(TRACE,
- "DisplayService::OnCreateSurface: surface_id=%d process_id=%d",
- surface_id, process_id);
-
- auto surface_status =
- DisplaySurface::Create(this, surface_id, process_id, user_id, attributes);
- if (!surface_status) {
- ALOGE("DisplayService::OnCreateSurface: Failed to create surface: %s",
- surface_status.GetErrorMessage().c_str());
- return ErrorStatus(surface_status.error());
- }
- auto surface = surface_status.take();
- message.SetChannel(surface);
-
- // Update the surface with the attributes supplied with the create call. For
- // application surfaces this has the side effect of notifying the display
- // manager of the new surface. For direct surfaces, this may trigger a mode
- // change, depending on the value of the visible attribute.
- surface->OnSetAttributes(message, attributes);
-
- return {{surface->surface_id(), surface->visible(), surface->z_order()}};
-}
-
-void DisplayService::SurfaceUpdated(SurfaceType surface_type,
- display::SurfaceUpdateFlags update_flags) {
- ALOGD_IF(TRACE, "DisplayService::SurfaceUpdated: update_flags=%x",
- update_flags.value());
- if (update_flags.value() != 0) {
- if (surface_type == SurfaceType::Application)
- NotifyDisplayConfigurationUpdate();
- else
- UpdateActiveDisplaySurfaces();
- }
-}
-
-pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnSetupGlobalBuffer(
- pdx::Message& message, DvrGlobalBufferKey key, size_t size,
- uint64_t usage) {
- const int user_id = message.GetEffectiveUserId();
- const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
-
- if (!trusted) {
- ALOGE(
- "DisplayService::OnSetupGlobalBuffer: Permission denied for user_id=%d",
- user_id);
- return ErrorStatus(EPERM);
- }
- return SetupGlobalBuffer(key, size, usage);
-}
-
-pdx::Status<void> DisplayService::OnDeleteGlobalBuffer(pdx::Message& message,
- DvrGlobalBufferKey key) {
- const int user_id = message.GetEffectiveUserId();
- const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
-
- if (!trusted) {
- ALOGE(
- "DisplayService::OnDeleteGlobalBuffer: Permission denied for "
- "user_id=%d",
- user_id);
- return ErrorStatus(EPERM);
- }
- return DeleteGlobalBuffer(key);
-}
-
-pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetGlobalBuffer(
- pdx::Message& /* message */, DvrGlobalBufferKey key) {
- ALOGD_IF(TRACE, "DisplayService::OnGetGlobalBuffer: key=%d", key);
- auto global_buffer = global_buffers_.find(key);
- if (global_buffer != global_buffers_.end())
- return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
- else
- return pdx::ErrorStatus(EINVAL);
-}
-
-// Calls the message handler for the DisplaySurface associated with this
-// channel.
-Status<void> DisplayService::HandleSurfaceMessage(pdx::Message& message) {
- auto surface = std::static_pointer_cast<DisplaySurface>(message.GetChannel());
- ALOGW_IF(!surface,
- "DisplayService::HandleSurfaceMessage: surface is nullptr!");
-
- if (surface)
- return surface->HandleMessage(message);
- else
- return ErrorStatus(EINVAL);
-}
-
-std::shared_ptr<DisplaySurface> DisplayService::GetDisplaySurface(
- int surface_id) const {
- return std::static_pointer_cast<DisplaySurface>(GetChannel(surface_id));
-}
-
-std::vector<std::shared_ptr<DisplaySurface>>
-DisplayService::GetDisplaySurfaces() const {
- return GetChannels<DisplaySurface>();
-}
-
-std::vector<std::shared_ptr<DirectDisplaySurface>>
-DisplayService::GetVisibleDisplaySurfaces() const {
- std::vector<std::shared_ptr<DirectDisplaySurface>> visible_surfaces;
-
- ForEachDisplaySurface(
- SurfaceType::Direct,
- [&](const std::shared_ptr<DisplaySurface>& surface) mutable {
- if (surface->visible()) {
- visible_surfaces.push_back(
- std::static_pointer_cast<DirectDisplaySurface>(surface));
- surface->ClearUpdate();
- }
- });
-
- return visible_surfaces;
-}
-
-void DisplayService::UpdateActiveDisplaySurfaces() {
- auto visible_surfaces = GetVisibleDisplaySurfaces();
- ALOGD_IF(TRACE,
- "DisplayService::UpdateActiveDisplaySurfaces: %zd visible surfaces",
- visible_surfaces.size());
- hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
-}
-
-pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupGlobalBuffer(
- DvrGlobalBufferKey key, size_t size, uint64_t usage) {
- auto global_buffer = global_buffers_.find(key);
- if (global_buffer == global_buffers_.end()) {
- auto ion_buffer = std::make_unique<IonBuffer>(static_cast<int>(size), 1,
- HAL_PIXEL_FORMAT_BLOB, usage);
-
- // Some buffers are used internally. If they were configured with an
- // invalid size or format, this will fail.
- int result = hardware_composer_.OnNewGlobalBuffer(key, *ion_buffer.get());
- if (result < 0)
- return ErrorStatus(result);
- global_buffer =
- global_buffers_.insert(std::make_pair(key, std::move(ion_buffer)))
- .first;
- }
-
- return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
-}
-
-pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
- auto global_buffer = global_buffers_.find(key);
- if (global_buffer != global_buffers_.end()) {
- // Some buffers are used internally.
- hardware_composer_.OnDeletedGlobalBuffer(key);
- global_buffers_.erase(global_buffer);
- }
-
- return {0};
-}
-
-void DisplayService::SetDisplayConfigurationUpdateNotifier(
- DisplayConfigurationUpdateNotifier update_notifier) {
- update_notifier_ = update_notifier;
-}
-
-void DisplayService::NotifyDisplayConfigurationUpdate() {
- if (update_notifier_)
- update_notifier_();
-}
-
-Status<bool> DisplayService::IsVrAppRunning(pdx::Message& /*message*/) {
- bool visible = false;
- ForEachDisplaySurface(
- SurfaceType::Application,
- [&visible](const std::shared_ptr<DisplaySurface>& surface) {
- if (surface->visible())
- visible = true;
- });
-
- return {visible};
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
deleted file mode 100644
index 89f1eae..0000000
--- a/libs/vr/libvrflinger/display_service.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_
-#define ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_
-
-#include <dvr/dvr_api.h>
-#include <pdx/service.h>
-#include <pdx/status.h>
-#include <private/dvr/bufferhub_rpc.h>
-#include <private/dvr/display_protocol.h>
-
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "acquired_buffer.h"
-#include "display_surface.h"
-#include "epoll_event_dispatcher.h"
-#include "hardware_composer.h"
-
-namespace android {
-namespace dvr {
-
-// DisplayService implements the display service component of VrFlinger.
-class DisplayService : public pdx::ServiceBase<DisplayService> {
- public:
- bool IsInitialized() const override;
- std::string DumpState(size_t max_length) override;
-
- void OnChannelClose(pdx::Message& message,
- const std::shared_ptr<pdx::Channel>& channel) override;
- pdx::Status<void> HandleMessage(pdx::Message& message) override;
-
- std::shared_ptr<DisplaySurface> GetDisplaySurface(int surface_id) const;
- std::vector<std::shared_ptr<DisplaySurface>> GetDisplaySurfaces() const;
- std::vector<std::shared_ptr<DirectDisplaySurface>> GetVisibleDisplaySurfaces()
- const;
-
- // Updates the list of actively displayed surfaces. This must be called after
- // any change to client/manager attributes that affect visibility or z order.
- void UpdateActiveDisplaySurfaces();
-
- pdx::Status<BorrowedNativeBufferHandle> SetupGlobalBuffer(
- DvrGlobalBufferKey key, size_t size, uint64_t usage);
-
- pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
-
- template <class A>
- void ForEachDisplaySurface(SurfaceType surface_type, A action) const {
- ForEachChannel([surface_type,
- action](const ChannelIterator::value_type& pair) mutable {
- auto surface = std::static_pointer_cast<DisplaySurface>(pair.second);
- if (surface->surface_type() == surface_type)
- action(surface);
- });
- }
-
- using DisplayConfigurationUpdateNotifier = std::function<void(void)>;
- void SetDisplayConfigurationUpdateNotifier(
- DisplayConfigurationUpdateNotifier notifier);
-
- void GrantDisplayOwnership() { hardware_composer_.Enable(); }
- void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
- void OnBootFinished() { hardware_composer_.OnBootFinished(); }
-
- private:
- friend BASE;
- friend DisplaySurface;
-
- friend class VrDisplayStateService;
-
- using RequestDisplayCallback = std::function<void(bool)>;
-
- DisplayService(android::Hwc2::Composer* hidl,
- hwc2_display_t primary_display_id,
- RequestDisplayCallback request_display_callback);
-
- pdx::Status<BorrowedNativeBufferHandle> OnGetGlobalBuffer(
- pdx::Message& message, DvrGlobalBufferKey key);
- pdx::Status<display::Metrics> OnGetMetrics(pdx::Message& message);
- pdx::Status<std::string> OnGetConfigurationData(
- pdx::Message& message, display::ConfigFileType config_type);
- pdx::Status<uint8_t> OnGetDisplayIdentificationPort(pdx::Message& message);
- pdx::Status<display::SurfaceInfo> OnCreateSurface(
- pdx::Message& message, const display::SurfaceAttributes& attributes);
- pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
- pdx::Message& message, DvrGlobalBufferKey key, size_t size,
- uint64_t usage);
- pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message,
- DvrGlobalBufferKey key);
-
- // Temporary query for current VR status. Will be removed later.
- pdx::Status<bool> IsVrAppRunning(pdx::Message& message);
-
- pdx::Status<void> AddEventHandler(int fd, int events,
- EpollEventDispatcher::Handler handler) {
- return dispatcher_.AddEventHandler(fd, events, handler);
- }
- pdx::Status<void> RemoveEventHandler(int fd) {
- return dispatcher_.RemoveEventHandler(fd);
- }
-
- void SurfaceUpdated(SurfaceType surface_type,
- display::SurfaceUpdateFlags update_flags);
-
- // Called by DisplaySurface to signal that a surface property has changed and
- // the display manager should be notified.
- void NotifyDisplayConfigurationUpdate();
-
- pdx::Status<void> HandleSurfaceMessage(pdx::Message& message);
-
- HardwareComposer hardware_composer_;
- EpollEventDispatcher dispatcher_;
- DisplayConfigurationUpdateNotifier update_notifier_;
-
- std::unordered_map<DvrGlobalBufferKey, std::unique_ptr<IonBuffer>>
- global_buffers_;
-
- DisplayService(const DisplayService&) = delete;
- void operator=(const DisplayService&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
deleted file mode 100644
index 87c823e..0000000
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ /dev/null
@@ -1,488 +0,0 @@
-#include "display_surface.h"
-
-#include <private/android_filesystem_config.h>
-#include <utils/Trace.h>
-
-#include <private/dvr/trusted_uids.h>
-
-#include "display_service.h"
-#include "hardware_composer.h"
-
-#define LOCAL_TRACE 1
-
-using android::dvr::display::DisplayProtocol;
-using android::pdx::BorrowedChannelHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-using android::pdx::rpc::IfAnyOf;
-
-namespace android {
-namespace dvr {
-
-DisplaySurface::DisplaySurface(DisplayService* service,
- SurfaceType surface_type, int surface_id,
- int process_id, int user_id)
- : service_(service),
- surface_type_(surface_type),
- surface_id_(surface_id),
- process_id_(process_id),
- user_id_(user_id),
- update_flags_(display::SurfaceUpdateFlags::NewSurface) {}
-
-DisplaySurface::~DisplaySurface() {
- ALOGD_IF(LOCAL_TRACE,
- "DisplaySurface::~DisplaySurface: surface_id=%d process_id=%d",
- surface_id(), process_id());
-}
-
-Status<void> DisplaySurface::HandleMessage(pdx::Message& message) {
- switch (message.GetOp()) {
- case DisplayProtocol::SetAttributes::Opcode:
- DispatchRemoteMethod<DisplayProtocol::SetAttributes>(
- *this, &DisplaySurface::OnSetAttributes, message);
- break;
-
- case DisplayProtocol::GetSurfaceInfo::Opcode:
- DispatchRemoteMethod<DisplayProtocol::GetSurfaceInfo>(
- *this, &DisplaySurface::OnGetSurfaceInfo, message);
- break;
-
- case DisplayProtocol::CreateQueue::Opcode:
- DispatchRemoteMethod<DisplayProtocol::CreateQueue>(
- *this, &DisplaySurface::OnCreateQueue, message);
- break;
- }
-
- return {};
-}
-
-Status<void> DisplaySurface::OnSetAttributes(
- pdx::Message& /*message*/, const display::SurfaceAttributes& attributes) {
- display::SurfaceUpdateFlags update_flags;
-
- for (const auto& attribute : attributes) {
- const auto key = attribute.first;
- const auto* variant = &attribute.second;
- bool invalid_value = false;
- bool visibility_changed = false;
-
- // Catch attributes that have significance to the display service.
- switch (key) {
- case display::SurfaceAttribute::ZOrder:
- invalid_value = !IfAnyOf<int32_t, int64_t, float>::Call(
- variant, [&](const auto& value) {
- if (z_order_ != value) {
- visibility_changed = true;
- z_order_ = value;
- }
- });
- break;
- case display::SurfaceAttribute::Visible:
- invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
- variant, [&](const auto& value) {
- if (visible_ != value) {
- visibility_changed = true;
- visible_ = value;
- }
- });
- break;
- }
-
- // Only update the attribute map with valid values. This check also has the
- // effect of preventing special attributes handled above from being deleted
- // by an empty value.
- if (invalid_value) {
- ALOGW(
- "DisplaySurface::OnClientSetAttributes: Failed to set display "
- "surface attribute '%d' because of incompatible type: %d",
- key, variant->index());
- } else {
- // An empty value indicates the attribute should be deleted.
- if (variant->empty()) {
- auto search = attributes_.find(key);
- if (search != attributes_.end())
- attributes_.erase(search);
- } else {
- attributes_[key] = *variant;
- }
-
- // All attribute changes generate a notification, even if the value
- // doesn't change. Visibility attributes set a flag only if the value
- // changes.
- update_flags.Set(display::SurfaceUpdateFlags::AttributesChanged);
- if (visibility_changed)
- update_flags.Set(display::SurfaceUpdateFlags::VisibilityChanged);
- }
- }
-
- SurfaceUpdated(update_flags);
- return {};
-}
-
-void DisplaySurface::SurfaceUpdated(display::SurfaceUpdateFlags update_flags) {
- ALOGD_IF(TRACE,
- "DisplaySurface::SurfaceUpdated: surface_id=%d update_flags=0x%x",
- surface_id(), update_flags.value());
-
- update_flags_.Set(update_flags);
- service()->SurfaceUpdated(surface_type(), update_flags_);
-}
-
-void DisplaySurface::ClearUpdate() {
- ALOGD_IF(TRACE > 1, "DisplaySurface::ClearUpdate: surface_id=%d",
- surface_id());
- update_flags_ = display::SurfaceUpdateFlags::None;
-}
-
-Status<display::SurfaceInfo> DisplaySurface::OnGetSurfaceInfo(
- Message& /*message*/) {
- ALOGD_IF(
- TRACE,
- "DisplaySurface::OnGetSurfaceInfo: surface_id=%d visible=%d z_order=%d",
- surface_id(), visible(), z_order());
- return {{surface_id(), visible(), z_order()}};
-}
-
-Status<void> DisplaySurface::RegisterQueue(
- const std::shared_ptr<ConsumerQueue>& consumer_queue) {
- ALOGD_IF(TRACE, "DisplaySurface::RegisterQueue: surface_id=%d queue_id=%d",
- surface_id(), consumer_queue->id());
- // Capture references for the lambda to work around apparent clang bug.
- // TODO(eieio): Figure out if there is a clang bug or C++11 ambiguity when
- // capturing self and consumer_queue by copy in the following case:
- // auto self = Self();
- // [self, consumer_queue](int events) {
- // self->OnQueueEvent(consuemr_queue, events); }
- //
- struct State {
- std::shared_ptr<DisplaySurface> surface;
- std::shared_ptr<ConsumerQueue> queue;
- };
- State state{Self(), consumer_queue};
-
- return service()->AddEventHandler(
- consumer_queue->queue_fd(), EPOLLIN | EPOLLHUP | EPOLLET,
- [state](int events) {
- state.surface->OnQueueEvent(state.queue, events);
- });
-}
-
-Status<void> DisplaySurface::UnregisterQueue(
- const std::shared_ptr<ConsumerQueue>& consumer_queue) {
- ALOGD_IF(TRACE, "DisplaySurface::UnregisterQueue: surface_id=%d queue_id=%d",
- surface_id(), consumer_queue->id());
- return service()->RemoveEventHandler(consumer_queue->queue_fd());
-}
-
-void DisplaySurface::OnQueueEvent(
- const std::shared_ptr<ConsumerQueue>& /*consumer_queue*/, int /*events*/) {
- ALOGE(
- "DisplaySurface::OnQueueEvent: ERROR base virtual method should not be "
- "called!!!");
-}
-
-std::shared_ptr<ConsumerQueue> ApplicationDisplaySurface::GetQueue(
- int32_t queue_id) {
- ALOGD_IF(TRACE,
- "ApplicationDisplaySurface::GetQueue: surface_id=%d queue_id=%d",
- surface_id(), queue_id);
-
- std::lock_guard<std::mutex> autolock(lock_);
- auto search = consumer_queues_.find(queue_id);
- if (search != consumer_queues_.end())
- return search->second;
- else
- return nullptr;
-}
-
-std::vector<int32_t> ApplicationDisplaySurface::GetQueueIds() const {
- std::lock_guard<std::mutex> autolock(lock_);
- std::vector<int32_t> queue_ids;
- for (const auto& entry : consumer_queues_)
- queue_ids.push_back(entry.first);
- return queue_ids;
-}
-
-Status<LocalChannelHandle> ApplicationDisplaySurface::OnCreateQueue(
- Message& /*message*/, const ProducerQueueConfig& config) {
- ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
- ALOGD_IF(TRACE,
- "ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
- "user_metadata_size=%zu",
- surface_id(), config.user_metadata_size);
-
- std::lock_guard<std::mutex> autolock(lock_);
- auto producer = ProducerQueue::Create(config, UsagePolicy{});
- if (!producer) {
- ALOGE(
- "ApplicationDisplaySurface::OnCreateQueue: Failed to create producer "
- "queue!");
- return ErrorStatus(ENOMEM);
- }
-
- std::shared_ptr<ConsumerQueue> consumer =
- producer->CreateSilentConsumerQueue();
- auto status = RegisterQueue(consumer);
- if (!status) {
- ALOGE(
- "ApplicationDisplaySurface::OnCreateQueue: Failed to register consumer "
- "queue: %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- consumer_queues_[consumer->id()] = std::move(consumer);
-
- SurfaceUpdated(display::SurfaceUpdateFlags::BuffersChanged);
- return std::move(producer->GetChannelHandle());
-}
-
-void ApplicationDisplaySurface::OnQueueEvent(
- const std::shared_ptr<ConsumerQueue>& consumer_queue, int events) {
- ALOGD_IF(TRACE,
- "ApplicationDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
- consumer_queue->id(), events);
-
- std::lock_guard<std::mutex> autolock(lock_);
-
- // Always give the queue a chance to handle its internal bookkeeping.
- consumer_queue->HandleQueueEvents();
-
- // Check for hangup and remove a queue that is no longer needed.
- if (consumer_queue->hung_up()) {
- ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: Removing queue.");
- UnregisterQueue(consumer_queue);
- auto search = consumer_queues_.find(consumer_queue->id());
- if (search != consumer_queues_.end()) {
- consumer_queues_.erase(search);
- } else {
- ALOGE(
- "ApplicationDisplaySurface::OnQueueEvent: Failed to find queue_id=%d",
- consumer_queue->id());
- }
- SurfaceUpdated(display::SurfaceUpdateFlags::BuffersChanged);
- }
-}
-
-std::vector<int32_t> DirectDisplaySurface::GetQueueIds() const {
- std::lock_guard<std::mutex> autolock(lock_);
- std::vector<int32_t> queue_ids;
- if (direct_queue_)
- queue_ids.push_back(direct_queue_->id());
- return queue_ids;
-}
-
-Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
- Message& /*message*/, const ProducerQueueConfig& config) {
- ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
- ALOGD_IF(TRACE,
- "DirectDisplaySurface::OnCreateQueue: surface_id=%d "
- "user_metadata_size=%zu",
- surface_id(), config.user_metadata_size);
-
- std::lock_guard<std::mutex> autolock(lock_);
- if (!direct_queue_) {
- // Inject the hw composer usage flag to enable the display to read the
- // buffers.
- auto producer = ProducerQueue::Create(
- config, UsagePolicy{GraphicBuffer::USAGE_HW_COMPOSER, 0, 0, 0});
- if (!producer) {
- ALOGE(
- "DirectDisplaySurface::OnCreateQueue: Failed to create producer "
- "queue!");
- return ErrorStatus(ENOMEM);
- }
-
- direct_queue_ = producer->CreateConsumerQueue();
- if (direct_queue_->metadata_size() > 0) {
- metadata_.reset(new uint8_t[direct_queue_->metadata_size()]);
- }
- auto status = RegisterQueue(direct_queue_);
- if (!status) {
- ALOGE(
- "DirectDisplaySurface::OnCreateQueue: Failed to register consumer "
- "queue: %s",
- status.GetErrorMessage().c_str());
- return status.error_status();
- }
-
- return std::move(producer->GetChannelHandle());
- } else {
- return ErrorStatus(EALREADY);
- }
-}
-
-void DirectDisplaySurface::OnQueueEvent(
- const std::shared_ptr<ConsumerQueue>& consumer_queue, int events) {
- ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
- consumer_queue->id(), events);
-
- std::lock_guard<std::mutex> autolock(lock_);
-
- // Always give the queue a chance to handle its internal bookkeeping.
- consumer_queue->HandleQueueEvents();
-
- // Check for hangup and remove a queue that is no longer needed.
- if (consumer_queue->hung_up()) {
- ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: Removing queue.");
- UnregisterQueue(consumer_queue);
- direct_queue_ = nullptr;
- }
-}
-
-void DirectDisplaySurface::DequeueBuffersLocked() {
- if (direct_queue_ == nullptr) {
- ALOGE(
- "DirectDisplaySurface::DequeueBuffersLocked: Consumer queue is not "
- "initialized.");
- return;
- }
-
- while (true) {
- LocalHandle acquire_fence;
- size_t slot;
- auto buffer_status = direct_queue_->Dequeue(
- 0, &slot, metadata_.get(),
- direct_queue_->metadata_size(), &acquire_fence);
- ALOGD_IF(TRACE,
- "DirectDisplaySurface::DequeueBuffersLocked: Dequeue with metadata_size: %zu",
- direct_queue_->metadata_size());
- if (!buffer_status) {
- ALOGD_IF(
- TRACE > 1 && buffer_status.error() == ETIMEDOUT,
- "DirectDisplaySurface::DequeueBuffersLocked: All buffers dequeued.");
- ALOGE_IF(buffer_status.error() != ETIMEDOUT,
- "DirectDisplaySurface::DequeueBuffersLocked: Failed to dequeue "
- "buffer: %s",
- buffer_status.GetErrorMessage().c_str());
- return;
- }
- auto buffer_consumer = buffer_status.take();
-
- if (!visible()) {
- ATRACE_NAME("DropFrameOnInvisibleSurface");
- ALOGD_IF(TRACE,
- "DirectDisplaySurface::DequeueBuffersLocked: Discarding "
- "buffer_id=%d on invisible surface.",
- buffer_consumer->id());
- buffer_consumer->Discard();
- continue;
- }
-
- if (acquired_buffers_.IsFull()) {
- ALOGE(
- "DirectDisplaySurface::DequeueBuffersLocked: Posted buffers full, "
- "overwriting.");
- acquired_buffers_.PopBack();
- }
-
- acquired_buffers_.Append(
- AcquiredBuffer(buffer_consumer, std::move(acquire_fence), slot));
- }
-}
-
-AcquiredBuffer DirectDisplaySurface::AcquireCurrentBuffer() {
- std::lock_guard<std::mutex> autolock(lock_);
- DequeueBuffersLocked();
-
- if (acquired_buffers_.IsEmpty()) {
- ALOGE(
- "DirectDisplaySurface::AcquireCurrentBuffer: attempt to acquire buffer "
- "when none are posted.");
- return AcquiredBuffer();
- }
- AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
- acquired_buffers_.PopFront();
- ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer_id=%d",
- buffer.buffer()->id());
- return buffer;
-}
-
-AcquiredBuffer DirectDisplaySurface::AcquireNewestAvailableBuffer(
- AcquiredBuffer* skipped_buffer) {
- std::lock_guard<std::mutex> autolock(lock_);
- DequeueBuffersLocked();
-
- AcquiredBuffer buffer;
- int frames = 0;
- // Basic latency stopgap for when the application misses a frame:
- // If the application recovers on the 2nd or 3rd (etc) frame after
- // missing, this code will skip frames to catch up by checking if
- // the next frame is also available.
- while (!acquired_buffers_.IsEmpty() &&
- acquired_buffers_.Front().IsAvailable()) {
- // Capture the skipped buffer into the result parameter.
- // Note that this API only supports skipping one buffer per vsync.
- if (frames > 0 && skipped_buffer)
- *skipped_buffer = std::move(buffer);
- ++frames;
- buffer = std::move(acquired_buffers_.Front());
- acquired_buffers_.PopFront();
- if (frames == 2)
- break;
- }
- ALOGD_IF(TRACE,
- "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer_id=%d",
- buffer.buffer()->id());
- return buffer;
-}
-
-bool DirectDisplaySurface::IsBufferAvailable() {
- std::lock_guard<std::mutex> autolock(lock_);
- DequeueBuffersLocked();
-
- return !acquired_buffers_.IsEmpty() &&
- acquired_buffers_.Front().IsAvailable();
-}
-
-bool DirectDisplaySurface::IsBufferPosted() {
- std::lock_guard<std::mutex> autolock(lock_);
- DequeueBuffersLocked();
-
- return !acquired_buffers_.IsEmpty();
-}
-
-Status<std::shared_ptr<DisplaySurface>> DisplaySurface::Create(
- DisplayService* service, int surface_id, int process_id, int user_id,
- const display::SurfaceAttributes& attributes) {
- bool direct = false;
- auto search = attributes.find(display::SurfaceAttribute::Direct);
- if (search != attributes.end()) {
- if (!IfAnyOf<int32_t, int64_t, bool, float>::Get(&search->second,
- &direct)) {
- ALOGE(
- "DisplaySurface::Create: Invalid type for SurfaceAttribute::Direct!");
- return ErrorStatus(EINVAL);
- }
- }
-
- ALOGD_IF(TRACE,
- "DisplaySurface::Create: surface_id=%d process_id=%d user_id=%d "
- "direct=%d",
- surface_id, process_id, user_id, direct);
-
- if (direct) {
- const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
- if (trusted) {
- return {std::shared_ptr<DisplaySurface>{
- new DirectDisplaySurface(service, surface_id, process_id, user_id)}};
- } else {
- ALOGE(
- "DisplaySurface::Create: Direct surfaces may only be created by "
- "trusted UIDs: user_id=%d",
- user_id);
- return ErrorStatus(EPERM);
- }
- } else {
- return {std::shared_ptr<DisplaySurface>{new ApplicationDisplaySurface(
- service, surface_id, process_id, user_id)}};
- }
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
deleted file mode 100644
index c8b1a07..0000000
--- a/libs/vr/libvrflinger/display_surface.h
+++ /dev/null
@@ -1,188 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SURFACE_H_
-#define ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SURFACE_H_
-
-#include <pdx/file_handle.h>
-#include <pdx/service.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/display_protocol.h>
-#include <private/dvr/ring_buffer.h>
-
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "acquired_buffer.h"
-
-namespace android {
-namespace dvr {
-
-class DisplayService;
-
-enum class SurfaceType {
- Direct,
- Application,
-};
-
-class DisplaySurface : public pdx::Channel {
- public:
- static pdx::Status<std::shared_ptr<DisplaySurface>> Create(
- DisplayService* service, int surface_id, int process_id, int user_id,
- const display::SurfaceAttributes& attributes);
-
- ~DisplaySurface() override;
-
- DisplayService* service() const { return service_; }
- SurfaceType surface_type() const { return surface_type_; }
- int surface_id() const { return surface_id_; }
- int process_id() const { return process_id_; }
- int user_id() const { return user_id_; }
-
- bool visible() const { return visible_; }
- int z_order() const { return z_order_; }
-
- const display::SurfaceAttributes& attributes() const { return attributes_; }
- display::SurfaceUpdateFlags update_flags() const { return update_flags_; }
-
- virtual std::vector<int32_t> GetQueueIds() const { return {}; }
-
- bool IsUpdatePending() const {
- return update_flags_.value() != display::SurfaceUpdateFlags::None;
- }
-
- protected:
- DisplaySurface(DisplayService* service, SurfaceType surface_type,
- int surface_id, int process_id, int user_id);
-
- // Utility to retrieve a shared pointer to this channel as the desired derived
- // type.
- template <
- typename T = DisplaySurface,
- typename = std::enable_if_t<std::is_base_of<DisplaySurface, T>::value>>
- std::shared_ptr<T> Self() {
- return std::static_pointer_cast<T>(shared_from_this());
- }
-
- virtual pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, const ProducerQueueConfig& config) = 0;
-
- // Registers a consumer queue with the event dispatcher in DisplayService. The
- // OnQueueEvent callback below is called to handle queue events.
- pdx::Status<void> RegisterQueue(
- const std::shared_ptr<ConsumerQueue>& consumer_queue);
- pdx::Status<void> UnregisterQueue(
- const std::shared_ptr<ConsumerQueue>& consumer_queue);
-
- // Called by the event dispatcher in DisplayService when a registered queue
- // event triggers. Executes on the event dispatcher thread.
- virtual void OnQueueEvent(
- const std::shared_ptr<ConsumerQueue>& consumer_queue, int events);
-
- void SurfaceUpdated(display::SurfaceUpdateFlags update_flags);
- void ClearUpdate();
-
- // Synchronizes access to mutable state below between message dispatch thread
- // and frame post thread.
- mutable std::mutex lock_;
-
- private:
- friend class DisplayService;
- friend class DisplayManagerService;
-
- // Dispatches display surface messages to the appropriate handlers. This
- // handler runs on the VrFlinger message dispatch thread.
- pdx::Status<void> HandleMessage(pdx::Message& message);
-
- pdx::Status<void> OnSetAttributes(
- pdx::Message& message, const display::SurfaceAttributes& attributes);
- pdx::Status<display::SurfaceInfo> OnGetSurfaceInfo(pdx::Message& message);
-
- DisplayService* service_;
- SurfaceType surface_type_;
- int surface_id_;
- int process_id_;
- int user_id_;
-
- display::SurfaceAttributes attributes_;
- display::SurfaceUpdateFlags update_flags_ = display::SurfaceUpdateFlags::None;
-
- // Subset of attributes that may be interpreted by the display service.
- bool visible_ = false;
- int z_order_ = 0;
-
- DisplaySurface(const DisplaySurface&) = delete;
- void operator=(const DisplaySurface&) = delete;
-};
-
-class ApplicationDisplaySurface : public DisplaySurface {
- public:
- ApplicationDisplaySurface(DisplayService* service, int surface_id,
- int process_id, int user_id)
- : DisplaySurface(service, SurfaceType::Application, surface_id,
- process_id, user_id) {}
-
- std::shared_ptr<ConsumerQueue> GetQueue(int32_t queue_id);
- std::vector<int32_t> GetQueueIds() const override;
-
- private:
- pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, const ProducerQueueConfig& config) override;
- void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
- int events) override;
-
- // Accessed by both message dispatch thread and epoll event thread.
- std::unordered_map<int32_t, std::shared_ptr<ConsumerQueue>> consumer_queues_;
-};
-
-class DirectDisplaySurface : public DisplaySurface {
- public:
- DirectDisplaySurface(DisplayService* service, int surface_id, int process_id,
- int user_id)
- : DisplaySurface(service, SurfaceType::Direct, surface_id, process_id,
- user_id),
- acquired_buffers_(kMaxPostedBuffers),
- metadata_(nullptr) {}
- std::vector<int32_t> GetQueueIds() const override;
- bool IsBufferAvailable();
- bool IsBufferPosted();
- AcquiredBuffer AcquireCurrentBuffer();
-
- // Get the newest buffer. Up to one buffer will be skipped. If a buffer is
- // skipped, it will be stored in skipped_buffer if non null.
- AcquiredBuffer AcquireNewestAvailableBuffer(AcquiredBuffer* skipped_buffer);
-
- private:
- pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, const ProducerQueueConfig& config) override;
- void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
- int events) override;
-
- // The capacity of the pending buffer queue. Should be enough to hold all the
- // buffers of this DisplaySurface, although in practice only 1 or 2 frames
- // will be pending at a time.
- static constexpr int kSurfaceBufferMaxCount = 4;
- static constexpr int kSurfaceViewMaxCount = 4;
- static constexpr int kMaxPostedBuffers =
- kSurfaceBufferMaxCount * kSurfaceViewMaxCount;
-
- // Returns whether a frame is available without locking the mutex.
- bool IsFrameAvailableNoLock() const;
-
- // Dequeue all available buffers from the consumer queue.
- void DequeueBuffersLocked();
-
- // In a triple-buffered surface, up to kMaxPostedBuffers buffers may be
- // posted and pending.
- RingBuffer<AcquiredBuffer> acquired_buffers_;
-
- std::shared_ptr<ConsumerQueue> direct_queue_;
-
- // Stores metadata when it dequeue buffers from consumer queue.
- std::unique_ptr<uint8_t[]> metadata_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SURFACE_H_
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
deleted file mode 100644
index 0d5eb80..0000000
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-#include "epoll_event_dispatcher.h"
-
-#include <log/log.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
-#include <sys/prctl.h>
-
-#include <dvr/performance_client_api.h>
-
-namespace android {
-namespace dvr {
-
-EpollEventDispatcher::EpollEventDispatcher() {
- epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
- if (!epoll_fd_) {
- ALOGE("Failed to create epoll fd: %s", strerror(errno));
- return;
- }
-
- event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
- if (!event_fd_) {
- ALOGE("Failed to create event for epolling: %s", strerror(errno));
- return;
- }
-
- // Add watch for eventfd. This should only watch for EPOLLIN, which gets set
- // when eventfd_write occurs. Use "this" as a unique sentinal value to
- // identify events from the event fd.
- epoll_event event = {.events = EPOLLIN, .data = {.ptr = this}};
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, event_fd_.Get(), &event) < 0) {
- ALOGE("Failed to add eventfd to epoll set because: %s", strerror(errno));
- return;
- }
-
- thread_ = std::thread(&EpollEventDispatcher::EventThread, this);
-}
-
-EpollEventDispatcher::~EpollEventDispatcher() { Stop(); }
-
-void EpollEventDispatcher::Stop() {
- exit_thread_.store(true);
- eventfd_write(event_fd_.Get(), 1);
-}
-
-pdx::Status<void> EpollEventDispatcher::AddEventHandler(int fd, int event_mask,
- Handler handler) {
- std::lock_guard<std::mutex> lock(lock_);
-
- epoll_event event;
- event.events = event_mask;
- event.data.ptr = &(handlers_[fd] = handler);
-
- ALOGD_IF(
- TRACE,
- "EpollEventDispatcher::AddEventHandler: fd=%d event_mask=0x%x handler=%p",
- fd, event_mask, event.data.ptr);
-
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, fd, &event) < 0) {
- const int error = errno;
- ALOGE("Failed to add fd to epoll set because: %s", strerror(error));
- return pdx::ErrorStatus(error);
- } else {
- return {};
- }
-}
-
-pdx::Status<void> EpollEventDispatcher::RemoveEventHandler(int fd) {
- ALOGD_IF(TRACE, "EpollEventDispatcher::RemoveEventHandler: fd=%d", fd);
- std::lock_guard<std::mutex> lock(lock_);
-
- epoll_event ee; // See BUGS in man 2 epoll_ctl.
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, fd, &ee) < 0) {
- const int error = errno;
- ALOGE("Failed to remove fd from epoll set because: %s", strerror(error));
- return pdx::ErrorStatus(error);
- }
-
- // If the fd was valid above, add it to the list of ids to remove.
- removed_handlers_.push_back(fd);
-
- // Wake up the event thread to clean up.
- eventfd_write(event_fd_.Get(), 1);
-
- return {};
-}
-
-void EpollEventDispatcher::EventThread() {
- prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrEvent"), 0, 0, 0);
-
- const int error = dvrSetSchedulerClass(0, "graphics");
- LOG_ALWAYS_FATAL_IF(
- error < 0,
- "EpollEventDispatcher::EventThread: Failed to set scheduler class: %s",
- strerror(-error));
-
- const size_t kMaxNumEvents = 128;
- epoll_event events[kMaxNumEvents];
-
- while (!exit_thread_.load()) {
- const int num_events = epoll_wait(epoll_fd_.Get(), events, kMaxNumEvents, -1);
- if (num_events < 0 && errno != EINTR)
- break;
-
- ALOGD_IF(TRACE > 1, "EpollEventDispatcher::EventThread: num_events=%d",
- num_events);
-
- for (int i = 0; i < num_events; i++) {
- ALOGD_IF(
- TRACE > 1,
- "EpollEventDispatcher::EventThread: event %d: handler=%p events=0x%x",
- i, events[i].data.ptr, events[i].events);
-
- if (events[i].data.ptr == this) {
- // Clear pending event on event_fd_. Serialize the read with respect to
- // writes from other threads.
- std::lock_guard<std::mutex> lock(lock_);
- eventfd_t value;
- eventfd_read(event_fd_.Get(), &value);
- } else {
- auto handler = reinterpret_cast<Handler*>(events[i].data.ptr);
- if (handler)
- (*handler)(events[i].events);
- }
- }
-
- // Remove any handlers that have been posted for removal. This is done here
- // instead of in RemoveEventHandler() to prevent races between the dispatch
- // thread and the code requesting the removal. Handlers are guaranteed to
- // stay alive between exiting epoll_wait() and the dispatch loop above.
- std::lock_guard<std::mutex> lock(lock_);
- for (auto handler_fd : removed_handlers_) {
- ALOGD_IF(TRACE,
- "EpollEventDispatcher::EventThread: removing handler: fd=%d",
- handler_fd);
- handlers_.erase(handler_fd);
- }
- removed_handlers_.clear();
- }
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.h b/libs/vr/libvrflinger/epoll_event_dispatcher.h
deleted file mode 100644
index eb687f4..0000000
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_DISPLAYD_EPOLL_EVENT_DISPATCHER_H_
-#define ANDROID_DVR_SERVICES_DISPLAYD_EPOLL_EVENT_DISPATCHER_H_
-
-#include <sys/epoll.h>
-
-#include <atomic>
-#include <functional>
-#include <mutex>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-#include <pdx/file_handle.h>
-#include <pdx/status.h>
-
-namespace android {
-namespace dvr {
-
-class EpollEventDispatcher {
- public:
- // Function type for event handlers. The handler receives a bitmask of the
- // epoll events that occurred on the file descriptor associated with the
- // handler.
- using Handler = std::function<void(int)>;
-
- EpollEventDispatcher();
- ~EpollEventDispatcher();
-
- // |handler| is called on the internal dispatch thread when |fd| is signaled
- // by events in |event_mask|.
- pdx::Status<void> AddEventHandler(int fd, int event_mask, Handler handler);
- pdx::Status<void> RemoveEventHandler(int fd);
-
- void Stop();
-
- private:
- void EventThread();
-
- std::thread thread_;
- std::atomic<bool> exit_thread_{false};
-
- // Protects handlers_ and removed_handlers_ and serializes operations on
- // epoll_fd_ and event_fd_.
- std::mutex lock_;
-
- // Maintains a map of fds to event handlers. This is primarily to keep any
- // references alive that may be bound in the std::function instances. It is
- // not used at dispatch time to avoid performance problems with different
- // versions of std::unordered_map.
- std::unordered_map<int, Handler> handlers_;
-
- // List of fds to be removed from the map. The actual removal is performed
- // by the event dispatch thread to avoid races.
- std::vector<int> removed_handlers_;
-
- pdx::LocalHandle epoll_fd_;
- pdx::LocalHandle event_fd_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_SERVICES_DISPLAYD_EPOLL_EVENT_DISPATCHER_H_
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
deleted file mode 100644
index 70f303b..0000000
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ /dev/null
@@ -1,1541 +0,0 @@
-#include "hardware_composer.h"
-
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-#include <cutils/sched_policy.h>
-#include <fcntl.h>
-#include <log/log.h>
-#include <poll.h>
-#include <stdint.h>
-#include <sync/sync.h>
-#include <sys/eventfd.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
-#include <sys/system_properties.h>
-#include <sys/timerfd.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include <utils/Trace.h>
-
-#include <algorithm>
-#include <chrono>
-#include <functional>
-#include <map>
-#include <sstream>
-#include <string>
-#include <tuple>
-
-#include <dvr/dvr_display_types.h>
-#include <dvr/performance_client_api.h>
-#include <private/dvr/clock_ns.h>
-#include <private/dvr/ion_buffer.h>
-
-using android::hardware::Return;
-using android::hardware::Void;
-using android::pdx::ErrorStatus;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
-using android::pdx::rpc::EmptyVariant;
-using android::pdx::rpc::IfAnyOf;
-
-using namespace std::chrono_literals;
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-const char kDvrPerformanceProperty[] = "sys.dvr.performance";
-
-const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
-
-// Surface flinger uses "VSYNC-sf" and "VSYNC-app" for its version of these
-// events. Name ours similarly.
-const char kVsyncTraceEventName[] = "VSYNC-vrflinger";
-
-// How long to wait after boot finishes before we turn the display off.
-constexpr int kBootFinishedDisplayOffTimeoutSec = 10;
-
-constexpr int kDefaultDisplayWidth = 1920;
-constexpr int kDefaultDisplayHeight = 1080;
-constexpr int64_t kDefaultVsyncPeriodNs = 16666667;
-// Hardware composer reports dpi as dots per thousand inches (dpi * 1000).
-constexpr int kDefaultDpi = 400000;
-
-// Get time offset from a vsync to when the pose for that vsync should be
-// predicted out to. For example, if scanout gets halfway through the frame
-// at the halfway point between vsyncs, then this could be half the period.
-// With global shutter displays, this should be changed to the offset to when
-// illumination begins. Low persistence adds a frame of latency, so we predict
-// to the center of the next frame.
-inline int64_t GetPosePredictionTimeOffset(int64_t vsync_period_ns) {
- return (vsync_period_ns * 150) / 100;
-}
-
-// Attempts to set the scheduler class and partiton for the current thread.
-// Returns true on success or false on failure.
-bool SetThreadPolicy(const std::string& scheduler_class,
- const std::string& partition) {
- int error = dvrSetSchedulerClass(0, scheduler_class.c_str());
- if (error < 0) {
- ALOGE(
- "SetThreadPolicy: Failed to set scheduler class \"%s\" for "
- "thread_id=%d: %s",
- scheduler_class.c_str(), gettid(), strerror(-error));
- return false;
- }
- error = dvrSetCpuPartition(0, partition.c_str());
- if (error < 0) {
- ALOGE(
- "SetThreadPolicy: Failed to set cpu partiton \"%s\" for thread_id=%d: "
- "%s",
- partition.c_str(), gettid(), strerror(-error));
- return false;
- }
- return true;
-}
-
-// Utility to generate scoped tracers with arguments.
-// TODO(eieio): Move/merge this into utils/Trace.h?
-class TraceArgs {
- public:
- template <typename... Args>
- explicit TraceArgs(const char* format, Args&&... args) {
- std::array<char, 1024> buffer;
- snprintf(buffer.data(), buffer.size(), format, std::forward<Args>(args)...);
- atrace_begin(ATRACE_TAG, buffer.data());
- }
-
- ~TraceArgs() { atrace_end(ATRACE_TAG); }
-
- private:
- TraceArgs(const TraceArgs&) = delete;
- void operator=(const TraceArgs&) = delete;
-};
-
-// Macro to define a scoped tracer with arguments. Uses PASTE(x, y) macro
-// defined in utils/Trace.h.
-#define TRACE_FORMAT(format, ...) \
- TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ }
-
-// Returns "primary" or "external". Useful for writing more readable logs.
-const char* GetDisplayName(bool is_primary) {
- return is_primary ? "primary" : "external";
-}
-
-} // anonymous namespace
-
-HardwareComposer::HardwareComposer()
- : initialized_(false), request_display_callback_(nullptr) {}
-
-HardwareComposer::~HardwareComposer(void) {
- UpdatePostThreadState(PostThreadState::Quit, true);
- if (post_thread_.joinable())
- post_thread_.join();
- composer_callback_->SetVsyncService(nullptr);
-}
-
-void HardwareComposer::UpdateEdidData(Hwc2::Composer* composer,
- hwc2_display_t hw_id) {
- const auto error = composer->getDisplayIdentificationData(
- hw_id, &display_port_, &display_identification_data_);
- if (error != android::hardware::graphics::composer::V2_1::Error::NONE) {
- if (error !=
- android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) {
- ALOGI("hardware_composer: identification data error\n");
- } else {
- ALOGI("hardware_composer: identification data unsupported\n");
- }
- }
-}
-
-bool HardwareComposer::Initialize(
- Hwc2::Composer* composer, hwc2_display_t primary_display_id,
- RequestDisplayCallback request_display_callback) {
- if (initialized_) {
- ALOGE("HardwareComposer::Initialize: already initialized.");
- return false;
- }
-
- request_display_callback_ = request_display_callback;
-
- primary_display_ = GetDisplayParams(composer, primary_display_id, true);
-
- vsync_service_ = new VsyncService;
- sp<IServiceManager> sm(defaultServiceManager());
- auto result = sm->addService(String16(VsyncService::GetServiceName()),
- vsync_service_, false);
- LOG_ALWAYS_FATAL_IF(result != android::OK,
- "addService(%s) failed", VsyncService::GetServiceName());
-
- post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
- LOG_ALWAYS_FATAL_IF(
- !post_thread_event_fd_,
- "HardwareComposer: Failed to create interrupt event fd : %s",
- strerror(errno));
-
- UpdateEdidData(composer, primary_display_id);
-
- post_thread_ = std::thread(&HardwareComposer::PostThread, this);
-
- initialized_ = true;
-
- return initialized_;
-}
-
-void HardwareComposer::Enable() {
- UpdatePostThreadState(PostThreadState::Suspended, false);
-}
-
-void HardwareComposer::Disable() {
- UpdatePostThreadState(PostThreadState::Suspended, true);
-
- std::unique_lock<std::mutex> lock(post_thread_mutex_);
- post_thread_ready_.wait(lock, [this] {
- return !post_thread_resumed_;
- });
-}
-
-void HardwareComposer::OnBootFinished() {
- std::lock_guard<std::mutex> lock(post_thread_mutex_);
- if (boot_finished_)
- return;
- boot_finished_ = true;
- post_thread_wait_.notify_one();
-}
-
-// Update the post thread quiescent state based on idle and suspended inputs.
-void HardwareComposer::UpdatePostThreadState(PostThreadStateType state,
- bool suspend) {
- std::unique_lock<std::mutex> lock(post_thread_mutex_);
-
- // Update the votes in the state variable before evaluating the effective
- // quiescent state. Any bits set in post_thread_state_ indicate that the post
- // thread should be suspended.
- if (suspend) {
- post_thread_state_ |= state;
- } else {
- post_thread_state_ &= ~state;
- }
-
- const bool quit = post_thread_state_ & PostThreadState::Quit;
- const bool effective_suspend = post_thread_state_ != PostThreadState::Active;
- if (quit) {
- post_thread_quiescent_ = true;
- eventfd_write(post_thread_event_fd_.Get(), 1);
- post_thread_wait_.notify_one();
- } else if (effective_suspend && !post_thread_quiescent_) {
- post_thread_quiescent_ = true;
- eventfd_write(post_thread_event_fd_.Get(), 1);
- } else if (!effective_suspend && post_thread_quiescent_) {
- post_thread_quiescent_ = false;
- eventfd_t value;
- eventfd_read(post_thread_event_fd_.Get(), &value);
- post_thread_wait_.notify_one();
- }
-}
-
-void HardwareComposer::CreateComposer() {
- if (composer_)
- return;
- composer_.reset(new Hwc2::impl::Composer("default"));
- composer_callback_ = new ComposerCallback;
- composer_->registerCallback(composer_callback_);
- LOG_ALWAYS_FATAL_IF(!composer_callback_->GotFirstHotplug(),
- "Registered composer callback but didn't get hotplug for primary"
- " display");
- composer_callback_->SetVsyncService(vsync_service_);
-}
-
-void HardwareComposer::OnPostThreadResumed() {
- ALOGI("OnPostThreadResumed");
- EnableDisplay(*target_display_, true);
-
- // Trigger target-specific performance mode change.
- property_set(kDvrPerformanceProperty, "performance");
-}
-
-void HardwareComposer::OnPostThreadPaused() {
- ALOGI("OnPostThreadPaused");
- retire_fence_fds_.clear();
- layers_.clear();
-
- // Phones create a new composer client on resume and destroy it on pause.
- if (composer_callback_ != nullptr) {
- composer_callback_->SetVsyncService(nullptr);
- composer_callback_ = nullptr;
- }
- composer_.reset(nullptr);
-
- // Trigger target-specific performance mode change.
- property_set(kDvrPerformanceProperty, "idle");
-}
-
-bool HardwareComposer::PostThreadCondWait(std::unique_lock<std::mutex>& lock,
- int timeout_sec,
- const std::function<bool()>& pred) {
- auto pred_with_quit = [&] {
- return pred() || (post_thread_state_ & PostThreadState::Quit);
- };
- if (timeout_sec >= 0) {
- post_thread_wait_.wait_for(lock, std::chrono::seconds(timeout_sec),
- pred_with_quit);
- } else {
- post_thread_wait_.wait(lock, pred_with_quit);
- }
- if (post_thread_state_ & PostThreadState::Quit) {
- ALOGI("HardwareComposer::PostThread: Quitting.");
- return true;
- }
- return false;
-}
-
-HWC::Error HardwareComposer::Validate(hwc2_display_t display) {
- uint32_t num_types;
- uint32_t num_requests;
- HWC::Error error =
- composer_->validateDisplay(display, &num_types, &num_requests);
-
- if (error == HWC2_ERROR_HAS_CHANGES) {
- ALOGE("Hardware composer has requested composition changes, "
- "which we don't support.");
- // Accept the changes anyway and see if we can get something on the screen.
- error = composer_->acceptDisplayChanges(display);
- }
-
- return error;
-}
-
-bool HardwareComposer::EnableVsync(const DisplayParams& display, bool enabled) {
- HWC::Error error = composer_->setVsyncEnabled(display.id,
- (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE
- : HWC2_VSYNC_DISABLE));
- if (error != HWC::Error::None) {
- ALOGE("Error attempting to %s vsync on %s display: %s",
- enabled ? "enable" : "disable", GetDisplayName(display.is_primary),
- error.to_string().c_str());
- }
- return error == HWC::Error::None;
-}
-
-bool HardwareComposer::SetPowerMode(const DisplayParams& display, bool active) {
- ALOGI("Turning %s display %s", GetDisplayName(display.is_primary),
- active ? "on" : "off");
- HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off;
- HWC::Error error = composer_->setPowerMode(display.id,
- power_mode.cast<Hwc2::IComposerClient::PowerMode>());
- if (error != HWC::Error::None) {
- ALOGE("Error attempting to turn %s display %s: %s",
- GetDisplayName(display.is_primary), active ? "on" : "off",
- error.to_string().c_str());
- }
- return error == HWC::Error::None;
-}
-
-bool HardwareComposer::EnableDisplay(const DisplayParams& display,
- bool enabled) {
- bool power_result;
- bool vsync_result;
- // When turning a display on, we set the power state then set vsync. When
- // turning a display off we do it in the opposite order.
- if (enabled) {
- power_result = SetPowerMode(display, enabled);
- vsync_result = EnableVsync(display, enabled);
- } else {
- vsync_result = EnableVsync(display, enabled);
- power_result = SetPowerMode(display, enabled);
- }
- return power_result && vsync_result;
-}
-
-HWC::Error HardwareComposer::Present(hwc2_display_t display) {
- int32_t present_fence;
- HWC::Error error = composer_->presentDisplay(display, &present_fence);
-
- // According to the documentation, this fence is signaled at the time of
- // vsync/DMA for physical displays.
- if (error == HWC::Error::None) {
- retire_fence_fds_.emplace_back(present_fence);
- } else {
- ATRACE_INT("HardwareComposer: PresentResult", error);
- }
-
- return error;
-}
-
-DisplayParams HardwareComposer::GetDisplayParams(
- Hwc2::Composer* composer, hwc2_display_t display, bool is_primary) {
- DisplayParams params;
- params.id = display;
- params.is_primary = is_primary;
-
- Hwc2::Config config;
- HWC::Error error = composer->getActiveConfig(display, &config);
-
- if (error == HWC::Error::None) {
- auto get_attr = [&](hwc2_attribute_t attr, const char* attr_name)
- -> std::optional<int32_t> {
- int32_t val;
- HWC::Error error = composer->getDisplayAttribute(
- display, config, (Hwc2::IComposerClient::Attribute)attr, &val);
- if (error != HWC::Error::None) {
- ALOGE("Failed to get %s display attr %s: %s",
- GetDisplayName(is_primary), attr_name,
- error.to_string().c_str());
- return std::nullopt;
- }
- return val;
- };
-
- auto width = get_attr(HWC2_ATTRIBUTE_WIDTH, "width");
- auto height = get_attr(HWC2_ATTRIBUTE_HEIGHT, "height");
-
- if (width && height) {
- params.width = *width;
- params.height = *height;
- } else {
- ALOGI("Failed to get width and/or height for %s display. Using default"
- " size %dx%d.", GetDisplayName(is_primary), kDefaultDisplayWidth,
- kDefaultDisplayHeight);
- params.width = kDefaultDisplayWidth;
- params.height = kDefaultDisplayHeight;
- }
-
- auto vsync_period = get_attr(HWC2_ATTRIBUTE_VSYNC_PERIOD, "vsync period");
- if (vsync_period) {
- params.vsync_period_ns = *vsync_period;
- } else {
- ALOGI("Failed to get vsync period for %s display. Using default vsync"
- " period %.2fms", GetDisplayName(is_primary),
- static_cast<float>(kDefaultVsyncPeriodNs) / 1000000);
- params.vsync_period_ns = kDefaultVsyncPeriodNs;
- }
-
- auto dpi_x = get_attr(HWC2_ATTRIBUTE_DPI_X, "DPI X");
- auto dpi_y = get_attr(HWC2_ATTRIBUTE_DPI_Y, "DPI Y");
- if (dpi_x && dpi_y) {
- params.dpi.x = *dpi_x;
- params.dpi.y = *dpi_y;
- } else {
- ALOGI("Failed to get dpi_x and/or dpi_y for %s display. Using default"
- " dpi %d.", GetDisplayName(is_primary), kDefaultDpi);
- params.dpi.x = kDefaultDpi;
- params.dpi.y = kDefaultDpi;
- }
- } else {
- ALOGE("HardwareComposer: Failed to get current %s display config: %d."
- " Using default display values.",
- GetDisplayName(is_primary), error.value);
- params.width = kDefaultDisplayWidth;
- params.height = kDefaultDisplayHeight;
- params.dpi.x = kDefaultDpi;
- params.dpi.y = kDefaultDpi;
- params.vsync_period_ns = kDefaultVsyncPeriodNs;
- }
-
- ALOGI(
- "HardwareComposer: %s display attributes: width=%d height=%d "
- "vsync_period_ns=%d DPI=%dx%d",
- GetDisplayName(is_primary),
- params.width,
- params.height,
- params.vsync_period_ns,
- params.dpi.x,
- params.dpi.y);
-
- return params;
-}
-
-std::string HardwareComposer::Dump() {
- std::unique_lock<std::mutex> lock(post_thread_mutex_);
- std::ostringstream stream;
-
- auto print_display_metrics = [&](const DisplayParams& params) {
- stream << GetDisplayName(params.is_primary)
- << " display metrics: " << params.width << "x"
- << params.height << " " << (params.dpi.x / 1000.0)
- << "x" << (params.dpi.y / 1000.0) << " dpi @ "
- << (1000000000.0 / params.vsync_period_ns) << " Hz"
- << std::endl;
- };
-
- print_display_metrics(primary_display_);
- if (external_display_)
- print_display_metrics(*external_display_);
-
- stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
- stream << "Active layers: " << layers_.size() << std::endl;
- stream << std::endl;
-
- for (size_t i = 0; i < layers_.size(); i++) {
- stream << "Layer " << i << ":";
- stream << " type=" << layers_[i].GetCompositionType().to_string();
- stream << " surface_id=" << layers_[i].GetSurfaceId();
- stream << " buffer_id=" << layers_[i].GetBufferId();
- stream << std::endl;
- }
- stream << std::endl;
-
- if (post_thread_resumed_) {
- stream << "Hardware Composer Debug Info:" << std::endl;
- stream << composer_->dumpDebugInfo();
- }
-
- return stream.str();
-}
-
-void HardwareComposer::PostLayers(hwc2_display_t display) {
- ATRACE_NAME("HardwareComposer::PostLayers");
-
- // Setup the hardware composer layers with current buffers.
- for (auto& layer : layers_) {
- layer.Prepare();
- }
-
- // Now that we have taken in a frame from the application, we have a chance
- // to drop the frame before passing the frame along to HWC.
- // If the display driver has become backed up, we detect it here and then
- // react by skipping this frame to catch up latency.
- while (!retire_fence_fds_.empty() &&
- (!retire_fence_fds_.front() ||
- sync_wait(retire_fence_fds_.front().Get(), 0) == 0)) {
- // There are only 2 fences in here, no performance problem to shift the
- // array of ints.
- retire_fence_fds_.erase(retire_fence_fds_.begin());
- }
-
- const bool is_fence_pending = static_cast<int32_t>(retire_fence_fds_.size()) >
- post_thread_config_.allowed_pending_fence_count;
-
- if (is_fence_pending) {
- ATRACE_INT("frame_skip_count", ++frame_skip_count_);
-
- ALOGW_IF(is_fence_pending,
- "Warning: dropping a frame to catch up with HWC (pending = %zd)",
- retire_fence_fds_.size());
-
- for (auto& layer : layers_) {
- layer.Drop();
- }
- return;
- } else {
- // Make the transition more obvious in systrace when the frame skip happens
- // above.
- ATRACE_INT("frame_skip_count", 0);
- }
-
-#if TRACE > 1
- for (size_t i = 0; i < layers_.size(); i++) {
- ALOGI("HardwareComposer::PostLayers: layer=%zu buffer_id=%d composition=%s",
- i, layers_[i].GetBufferId(),
- layers_[i].GetCompositionType().to_string().c_str());
- }
-#endif
-
- HWC::Error error = Validate(display);
- if (error != HWC::Error::None) {
- ALOGE("HardwareComposer::PostLayers: Validate failed: %s display=%" PRIu64,
- error.to_string().c_str(), display);
- return;
- }
-
- error = Present(display);
- if (error != HWC::Error::None) {
- ALOGE("HardwareComposer::PostLayers: Present failed: %s",
- error.to_string().c_str());
- return;
- }
-
- std::vector<Hwc2::Layer> out_layers;
- std::vector<int> out_fences;
- error = composer_->getReleaseFences(display,
- &out_layers, &out_fences);
- ALOGE_IF(error != HWC::Error::None,
- "HardwareComposer::PostLayers: Failed to get release fences: %s",
- error.to_string().c_str());
-
- // Perform post-frame bookkeeping.
- uint32_t num_elements = out_layers.size();
- for (size_t i = 0; i < num_elements; ++i) {
- for (auto& layer : layers_) {
- if (layer.GetLayerHandle() == out_layers[i]) {
- layer.Finish(out_fences[i]);
- }
- }
- }
-}
-
-void HardwareComposer::SetDisplaySurfaces(
- std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces) {
- ALOGI("HardwareComposer::SetDisplaySurfaces: surface count=%zd",
- surfaces.size());
- const bool display_idle = surfaces.size() == 0;
- {
- std::unique_lock<std::mutex> lock(post_thread_mutex_);
- surfaces_ = std::move(surfaces);
- surfaces_changed_ = true;
- }
-
- if (request_display_callback_)
- request_display_callback_(!display_idle);
-
- // Set idle state based on whether there are any surfaces to handle.
- UpdatePostThreadState(PostThreadState::Idle, display_idle);
-}
-
-int HardwareComposer::OnNewGlobalBuffer(DvrGlobalBufferKey key,
- IonBuffer& ion_buffer) {
- if (key == DvrGlobalBuffers::kVsyncBuffer) {
- vsync_ring_ = std::make_unique<CPUMappedBroadcastRing<DvrVsyncRing>>(
- &ion_buffer, CPUUsageMode::WRITE_OFTEN);
-
- if (vsync_ring_->IsMapped() == false) {
- return -EPERM;
- }
- }
-
- if (key == DvrGlobalBuffers::kVrFlingerConfigBufferKey) {
- return MapConfigBuffer(ion_buffer);
- }
-
- return 0;
-}
-
-void HardwareComposer::OnDeletedGlobalBuffer(DvrGlobalBufferKey key) {
- if (key == DvrGlobalBuffers::kVrFlingerConfigBufferKey) {
- ConfigBufferDeleted();
- }
-}
-
-int HardwareComposer::MapConfigBuffer(IonBuffer& ion_buffer) {
- std::lock_guard<std::mutex> lock(shared_config_mutex_);
- shared_config_ring_ = DvrConfigRing();
-
- if (ion_buffer.width() < DvrConfigRing::MemorySize()) {
- ALOGE("HardwareComposer::MapConfigBuffer: invalid buffer size.");
- return -EINVAL;
- }
-
- void* buffer_base = 0;
- int result = ion_buffer.Lock(ion_buffer.usage(), 0, 0, ion_buffer.width(),
- ion_buffer.height(), &buffer_base);
- if (result != 0) {
- ALOGE(
- "HardwareComposer::MapConfigBuffer: Failed to map vrflinger config "
- "buffer.");
- return -EPERM;
- }
-
- shared_config_ring_ = DvrConfigRing::Create(buffer_base, ion_buffer.width());
- ion_buffer.Unlock();
-
- return 0;
-}
-
-void HardwareComposer::ConfigBufferDeleted() {
- std::lock_guard<std::mutex> lock(shared_config_mutex_);
- shared_config_ring_ = DvrConfigRing();
-}
-
-void HardwareComposer::UpdateConfigBuffer() {
- std::lock_guard<std::mutex> lock(shared_config_mutex_);
- if (!shared_config_ring_.is_valid())
- return;
- // Copy from latest record in shared_config_ring_ to local copy.
- DvrConfig record;
- if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) {
- ALOGI("DvrConfig updated: sequence %u, post offset %d",
- shared_config_ring_sequence_, record.frame_post_offset_ns);
- ++shared_config_ring_sequence_;
- post_thread_config_ = record;
- }
-}
-
-int HardwareComposer::PostThreadPollInterruptible(
- const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms) {
- pollfd pfd[2] = {
- {
- .fd = event_fd.Get(),
- .events = static_cast<short>(requested_events),
- .revents = 0,
- },
- {
- .fd = post_thread_event_fd_.Get(),
- .events = POLLPRI | POLLIN,
- .revents = 0,
- },
- };
- int ret, error;
- do {
- ret = poll(pfd, 2, timeout_ms);
- error = errno;
- ALOGW_IF(ret < 0,
- "HardwareComposer::PostThreadPollInterruptible: Error during "
- "poll(): %s (%d)",
- strerror(error), error);
- } while (ret < 0 && error == EINTR);
-
- if (ret < 0) {
- return -error;
- } else if (ret == 0) {
- return -ETIMEDOUT;
- } else if (pfd[0].revents != 0) {
- return 0;
- } else if (pfd[1].revents != 0) {
- ALOGI("VrHwcPost thread interrupted: revents=%x", pfd[1].revents);
- return kPostThreadInterrupted;
- } else {
- return 0;
- }
-}
-
-// Sleep until the next predicted vsync, returning the predicted vsync
-// timestamp.
-Status<int64_t> HardwareComposer::WaitForPredictedVSync() {
- const int64_t predicted_vsync_time = last_vsync_timestamp_ +
- (target_display_->vsync_period_ns * vsync_prediction_interval_);
- const int error = SleepUntil(predicted_vsync_time);
- if (error < 0) {
- ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s",
- strerror(-error));
- return error;
- }
- return {predicted_vsync_time};
-}
-
-int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) {
- const int timer_fd = vsync_sleep_timer_fd_.Get();
- const itimerspec wakeup_itimerspec = {
- .it_interval = {.tv_sec = 0, .tv_nsec = 0},
- .it_value = NsToTimespec(wakeup_timestamp),
- };
- int ret =
- timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &wakeup_itimerspec, nullptr);
- int error = errno;
- if (ret < 0) {
- ALOGE("HardwareComposer::SleepUntil: Failed to set timerfd: %s",
- strerror(error));
- return -error;
- }
-
- return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN,
- /*timeout_ms*/ -1);
-}
-
-void HardwareComposer::PostThread() {
- // NOLINTNEXTLINE(runtime/int)
- prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrHwcPost"), 0, 0, 0);
-
- // Set the scheduler to SCHED_FIFO with high priority. If this fails here
- // there may have been a startup timing issue between this thread and
- // performanced. Try again later when this thread becomes active.
- bool thread_policy_setup =
- SetThreadPolicy("graphics:high", "/system/performance");
-
- // Create a timerfd based on CLOCK_MONOTINIC.
- vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
- LOG_ALWAYS_FATAL_IF(
- !vsync_sleep_timer_fd_,
- "HardwareComposer: Failed to create vsync sleep timerfd: %s",
- strerror(errno));
-
- struct VsyncEyeOffsets { int64_t left_ns, right_ns; };
- bool was_running = false;
-
- auto get_vsync_eye_offsets = [this]() -> VsyncEyeOffsets {
- VsyncEyeOffsets offsets;
- offsets.left_ns =
- GetPosePredictionTimeOffset(target_display_->vsync_period_ns);
-
- // TODO(jbates) Query vblank time from device, when such an API is
- // available. This value (6.3%) was measured on A00 in low persistence mode.
- int64_t vblank_ns = target_display_->vsync_period_ns * 63 / 1000;
- offsets.right_ns = (target_display_->vsync_period_ns - vblank_ns) / 2;
-
- // Check property for overriding right eye offset value.
- offsets.right_ns =
- property_get_int64(kRightEyeOffsetProperty, offsets.right_ns);
-
- return offsets;
- };
-
- VsyncEyeOffsets vsync_eye_offsets = get_vsync_eye_offsets();
-
- while (1) {
- ATRACE_NAME("HardwareComposer::PostThread");
-
- // Check for updated config once per vsync.
- UpdateConfigBuffer();
-
- while (post_thread_quiescent_) {
- std::unique_lock<std::mutex> lock(post_thread_mutex_);
- ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
-
- if (was_running) {
- vsync_trace_parity_ = false;
- ATRACE_INT(kVsyncTraceEventName, 0);
- }
-
- // Tear down resources.
- OnPostThreadPaused();
- was_running = false;
- post_thread_resumed_ = false;
- post_thread_ready_.notify_all();
-
- if (PostThreadCondWait(lock, -1,
- [this] { return !post_thread_quiescent_; })) {
- // A true return value means we've been asked to quit.
- return;
- }
-
- post_thread_resumed_ = true;
- post_thread_ready_.notify_all();
-
- ALOGI("HardwareComposer::PostThread: Exiting quiescent state.");
- }
-
- if (!composer_)
- CreateComposer();
-
- bool target_display_changed = UpdateTargetDisplay();
- bool just_resumed_running = !was_running;
- was_running = true;
-
- if (target_display_changed)
- vsync_eye_offsets = get_vsync_eye_offsets();
-
- if (just_resumed_running) {
- OnPostThreadResumed();
-
- // Try to setup the scheduler policy if it failed during startup. Only
- // attempt to do this on transitions from inactive to active to avoid
- // spamming the system with RPCs and log messages.
- if (!thread_policy_setup) {
- thread_policy_setup =
- SetThreadPolicy("graphics:high", "/system/performance");
- }
- }
-
- if (target_display_changed || just_resumed_running) {
- // Initialize the last vsync timestamp with the current time. The
- // predictor below uses this time + the vsync interval in absolute time
- // units for the initial delay. Once the driver starts reporting vsync the
- // predictor will sync up with the real vsync.
- last_vsync_timestamp_ = GetSystemClockNs();
- vsync_prediction_interval_ = 1;
- retire_fence_fds_.clear();
- }
-
- int64_t vsync_timestamp = 0;
- {
- TRACE_FORMAT("wait_vsync|vsync=%u;last_timestamp=%" PRId64
- ";prediction_interval=%d|",
- vsync_count_ + 1, last_vsync_timestamp_,
- vsync_prediction_interval_);
-
- auto status = WaitForPredictedVSync();
- ALOGE_IF(
- !status,
- "HardwareComposer::PostThread: Failed to wait for vsync event: %s",
- status.GetErrorMessage().c_str());
-
- // If there was an error either sleeping was interrupted due to pausing or
- // there was an error getting the latest timestamp.
- if (!status)
- continue;
-
- // Predicted vsync timestamp for this interval. This is stable because we
- // use absolute time for the wakeup timer.
- vsync_timestamp = status.get();
- }
-
- vsync_trace_parity_ = !vsync_trace_parity_;
- ATRACE_INT(kVsyncTraceEventName, vsync_trace_parity_ ? 1 : 0);
-
- // Advance the vsync counter only if the system is keeping up with hardware
- // vsync to give clients an indication of the delays.
- if (vsync_prediction_interval_ == 1)
- ++vsync_count_;
-
- UpdateLayerConfig();
-
- // Publish the vsync event.
- if (vsync_ring_) {
- DvrVsync vsync;
- vsync.vsync_count = vsync_count_;
- vsync.vsync_timestamp_ns = vsync_timestamp;
- vsync.vsync_left_eye_offset_ns = vsync_eye_offsets.left_ns;
- vsync.vsync_right_eye_offset_ns = vsync_eye_offsets.right_ns;
- vsync.vsync_period_ns = target_display_->vsync_period_ns;
-
- vsync_ring_->Publish(vsync);
- }
-
- {
- // Sleep until shortly before vsync.
- ATRACE_NAME("sleep");
-
- const int64_t display_time_est_ns =
- vsync_timestamp + target_display_->vsync_period_ns;
- const int64_t now_ns = GetSystemClockNs();
- const int64_t sleep_time_ns = display_time_est_ns - now_ns -
- post_thread_config_.frame_post_offset_ns;
- const int64_t wakeup_time_ns =
- display_time_est_ns - post_thread_config_.frame_post_offset_ns;
-
- ATRACE_INT64("sleep_time_ns", sleep_time_ns);
- if (sleep_time_ns > 0) {
- int error = SleepUntil(wakeup_time_ns);
- ALOGE_IF(error < 0 && error != kPostThreadInterrupted,
- "HardwareComposer::PostThread: Failed to sleep: %s",
- strerror(-error));
- // If the sleep was interrupted (error == kPostThreadInterrupted),
- // we still go through and present this frame because we may have set
- // layers earlier and we want to flush the Composer's internal command
- // buffer by continuing through to validate and present.
- }
- }
-
- {
- auto status = composer_callback_->GetVsyncTime(target_display_->id);
-
- // If we failed to read vsync there might be a problem with the driver.
- // Since there's nothing we can do just behave as though we didn't get an
- // updated vsync time and let the prediction continue.
- const int64_t current_vsync_timestamp =
- status ? status.get() : last_vsync_timestamp_;
-
- const bool vsync_delayed =
- last_vsync_timestamp_ == current_vsync_timestamp;
- ATRACE_INT("vsync_delayed", vsync_delayed);
-
- // If vsync was delayed advance the prediction interval and allow the
- // fence logic in PostLayers() to skip the frame.
- if (vsync_delayed) {
- ALOGW(
- "HardwareComposer::PostThread: VSYNC timestamp did not advance "
- "since last frame: timestamp=%" PRId64 " prediction_interval=%d",
- current_vsync_timestamp, vsync_prediction_interval_);
- vsync_prediction_interval_++;
- } else {
- // We have an updated vsync timestamp, reset the prediction interval.
- last_vsync_timestamp_ = current_vsync_timestamp;
- vsync_prediction_interval_ = 1;
- }
- }
-
- PostLayers(target_display_->id);
- }
-}
-
-bool HardwareComposer::UpdateTargetDisplay() {
- bool target_display_changed = false;
- auto displays = composer_callback_->GetDisplays();
- if (displays.external_display_was_hotplugged) {
- bool was_using_external_display = !target_display_->is_primary;
- if (was_using_external_display) {
- // The external display was hotplugged, so make sure to ignore any bad
- // display errors as we destroy the layers.
- for (auto& layer: layers_)
- layer.IgnoreBadDisplayErrorsOnDestroy(true);
- }
-
- if (displays.external_display) {
- // External display was connected
- external_display_ = GetDisplayParams(composer_.get(),
- *displays.external_display, /*is_primary*/ false);
-
- ALOGI("External display connected. Switching to external display.");
- target_display_ = &(*external_display_);
- target_display_changed = true;
- } else {
- // External display was disconnected
- external_display_ = std::nullopt;
- if (was_using_external_display) {
- ALOGI("External display disconnected. Switching to primary display.");
- target_display_ = &primary_display_;
- target_display_changed = true;
- }
- }
- }
-
- if (target_display_changed) {
- // If we're switching to the external display, turn the primary display off.
- if (!target_display_->is_primary) {
- EnableDisplay(primary_display_, false);
- }
- // If we're switching to the primary display, and the external display is
- // still connected, turn the external display off.
- else if (target_display_->is_primary && external_display_) {
- EnableDisplay(*external_display_, false);
- }
-
- // Update the cached edid data for the current display.
- UpdateEdidData(composer_.get(), target_display_->id);
-
- // Turn the new target display on.
- EnableDisplay(*target_display_, true);
-
- // When we switch displays we need to recreate all the layers, so clear the
- // current list, which will trigger layer recreation.
- layers_.clear();
- }
-
- return target_display_changed;
-}
-
-// Checks for changes in the surface stack and updates the layer config to
-// accomodate the new stack.
-void HardwareComposer::UpdateLayerConfig() {
- std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces;
- {
- std::unique_lock<std::mutex> lock(post_thread_mutex_);
-
- if (!surfaces_changed_ && (!layers_.empty() || surfaces_.empty()))
- return;
-
- surfaces = surfaces_;
- surfaces_changed_ = false;
- }
-
- ATRACE_NAME("UpdateLayerConfig_HwLayers");
-
- // Sort the new direct surface list by z-order to determine the relative order
- // of the surfaces. This relative order is used for the HWC z-order value to
- // insulate VrFlinger and HWC z-order semantics from each other.
- std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
- return a->z_order() < b->z_order();
- });
-
- // Prepare a new layer stack, pulling in layers from the previous
- // layer stack that are still active and updating their attributes.
- std::vector<Layer> layers;
- size_t layer_index = 0;
- for (const auto& surface : surfaces) {
- // The bottom layer is opaque, other layers blend.
- HWC::BlendMode blending =
- layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage;
-
- // Try to find a layer for this surface in the set of active layers.
- auto search =
- std::lower_bound(layers_.begin(), layers_.end(), surface->surface_id());
- const bool found = search != layers_.end() &&
- search->GetSurfaceId() == surface->surface_id();
- if (found) {
- // Update the attributes of the layer that may have changed.
- search->SetBlending(blending);
- search->SetZOrder(layer_index); // Relative z-order.
-
- // Move the existing layer to the new layer set and remove the empty layer
- // object from the current set.
- layers.push_back(std::move(*search));
- layers_.erase(search);
- } else {
- // Insert a layer for the new surface.
- layers.emplace_back(composer_.get(), *target_display_, surface, blending,
- HWC::Composition::Device, layer_index);
- }
-
- ALOGI_IF(
- TRACE,
- "HardwareComposer::UpdateLayerConfig: layer_index=%zu surface_id=%d",
- layer_index, layers[layer_index].GetSurfaceId());
-
- layer_index++;
- }
-
- // Sort the new layer stack by ascending surface id.
- std::sort(layers.begin(), layers.end());
-
- // Replace the previous layer set with the new layer set. The destructor of
- // the previous set will clean up the remaining Layers that are not moved to
- // the new layer set.
- layers_ = std::move(layers);
-
- ALOGD_IF(TRACE, "HardwareComposer::UpdateLayerConfig: %zd active layers",
- layers_.size());
-}
-
-std::vector<sp<IVsyncCallback>>::const_iterator
-HardwareComposer::VsyncService::FindCallback(
- const sp<IVsyncCallback>& callback) const {
- sp<IBinder> binder = IInterface::asBinder(callback);
- return std::find_if(callbacks_.cbegin(), callbacks_.cend(),
- [&](const sp<IVsyncCallback>& callback) {
- return IInterface::asBinder(callback) == binder;
- });
-}
-
-status_t HardwareComposer::VsyncService::registerCallback(
- const sp<IVsyncCallback> callback) {
- std::lock_guard<std::mutex> autolock(mutex_);
- if (FindCallback(callback) == callbacks_.cend()) {
- callbacks_.push_back(callback);
- }
- return OK;
-}
-
-status_t HardwareComposer::VsyncService::unregisterCallback(
- const sp<IVsyncCallback> callback) {
- std::lock_guard<std::mutex> autolock(mutex_);
- auto iter = FindCallback(callback);
- if (iter != callbacks_.cend()) {
- callbacks_.erase(iter);
- }
- return OK;
-}
-
-void HardwareComposer::VsyncService::OnVsync(int64_t vsync_timestamp) {
- ATRACE_NAME("VsyncService::OnVsync");
- std::lock_guard<std::mutex> autolock(mutex_);
- for (auto iter = callbacks_.begin(); iter != callbacks_.end();) {
- if ((*iter)->onVsync(vsync_timestamp) == android::DEAD_OBJECT) {
- iter = callbacks_.erase(iter);
- } else {
- ++iter;
- }
- }
-}
-
-Return<void> HardwareComposer::ComposerCallback::onHotplug(
- Hwc2::Display display, IComposerCallback::Connection conn) {
- std::lock_guard<std::mutex> lock(mutex_);
- ALOGI("onHotplug display=%" PRIu64 " conn=%d", display, conn);
-
- bool is_primary = !got_first_hotplug_ || display == primary_display_.id;
-
- // Our first onHotplug callback is always for the primary display.
- if (!got_first_hotplug_) {
- LOG_ALWAYS_FATAL_IF(conn != IComposerCallback::Connection::CONNECTED,
- "Initial onHotplug callback should be primary display connected");
- got_first_hotplug_ = true;
- } else if (is_primary) {
- ALOGE("Ignoring unexpected onHotplug() call for primary display");
- return Void();
- }
-
- if (conn == IComposerCallback::Connection::CONNECTED) {
- if (!is_primary)
- external_display_ = DisplayInfo();
- DisplayInfo& display_info = is_primary ?
- primary_display_ : *external_display_;
- display_info.id = display;
-
- std::array<char, 1024> buffer;
- snprintf(buffer.data(), buffer.size(),
- "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display);
- if (LocalHandle handle{buffer.data(), O_RDONLY}) {
- ALOGI(
- "HardwareComposer::ComposerCallback::onHotplug: Driver supports "
- "vsync_event node for display %" PRIu64,
- display);
- display_info.driver_vsync_event_fd = std::move(handle);
- } else {
- ALOGI(
- "HardwareComposer::ComposerCallback::onHotplug: Driver does not "
- "support vsync_event node for display %" PRIu64,
- display);
- }
- } else if (conn == IComposerCallback::Connection::DISCONNECTED) {
- external_display_ = std::nullopt;
- }
-
- if (!is_primary)
- external_display_was_hotplugged_ = true;
-
- return Void();
-}
-
-Return<void> HardwareComposer::ComposerCallback::onRefresh(
- Hwc2::Display /*display*/) {
- return hardware::Void();
-}
-
-Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
- int64_t timestamp) {
- TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
- display, timestamp);
- std::lock_guard<std::mutex> lock(mutex_);
- DisplayInfo* display_info = GetDisplayInfo(display);
- if (display_info) {
- display_info->callback_vsync_timestamp = timestamp;
- }
- if (primary_display_.id == display && vsync_service_ != nullptr) {
- vsync_service_->OnVsync(timestamp);
- }
-
- return Void();
-}
-
-Return<void> HardwareComposer::ComposerCallback::onVsync_2_4(
- Hwc2::Display /*display*/, int64_t /*timestamp*/,
- Hwc2::VsyncPeriodNanos /*vsyncPeriodNanos*/) {
- LOG_ALWAYS_FATAL("Unexpected onVsync_2_4 callback");
- return Void();
-}
-
-Return<void> HardwareComposer::ComposerCallback::onVsyncPeriodTimingChanged(
- Hwc2::Display /*display*/,
- const Hwc2::VsyncPeriodChangeTimeline& /*updatedTimeline*/) {
- LOG_ALWAYS_FATAL("Unexpected onVsyncPeriodTimingChanged callback");
- return Void();
-}
-
-Return<void> HardwareComposer::ComposerCallback::onSeamlessPossible(
- Hwc2::Display /*display*/) {
- LOG_ALWAYS_FATAL("Unexpected onSeamlessPossible callback");
- return Void();
-}
-
-void HardwareComposer::ComposerCallback::SetVsyncService(
- const sp<VsyncService>& vsync_service) {
- std::lock_guard<std::mutex> lock(mutex_);
- vsync_service_ = vsync_service;
-}
-
-HardwareComposer::ComposerCallback::Displays
-HardwareComposer::ComposerCallback::GetDisplays() {
- std::lock_guard<std::mutex> lock(mutex_);
- Displays displays;
- displays.primary_display = primary_display_.id;
- if (external_display_)
- displays.external_display = external_display_->id;
- if (external_display_was_hotplugged_) {
- external_display_was_hotplugged_ = false;
- displays.external_display_was_hotplugged = true;
- }
- return displays;
-}
-
-Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
- hwc2_display_t display) {
- std::lock_guard<std::mutex> autolock(mutex_);
- DisplayInfo* display_info = GetDisplayInfo(display);
- if (!display_info) {
- ALOGW("Attempt to get vsync time for unknown display %" PRIu64, display);
- return ErrorStatus(EINVAL);
- }
-
- // See if the driver supports direct vsync events.
- LocalHandle& event_fd = display_info->driver_vsync_event_fd;
- if (!event_fd) {
- // Fall back to returning the last timestamp returned by the vsync
- // callback.
- return display_info->callback_vsync_timestamp;
- }
-
- // When the driver supports the vsync_event sysfs node we can use it to
- // determine the latest vsync timestamp, even if the HWC callback has been
- // delayed.
-
- // The driver returns data in the form "VSYNC=<timestamp ns>".
- std::array<char, 32> data;
- data.fill('\0');
-
- // Seek back to the beginning of the event file.
- int ret = lseek(event_fd.Get(), 0, SEEK_SET);
- if (ret < 0) {
- const int error = errno;
- ALOGE(
- "HardwareComposer::ComposerCallback::GetVsyncTime: Failed to seek "
- "vsync event fd: %s",
- strerror(error));
- return ErrorStatus(error);
- }
-
- // Read the vsync event timestamp.
- ret = read(event_fd.Get(), data.data(), data.size());
- if (ret < 0) {
- const int error = errno;
- ALOGE_IF(error != EAGAIN,
- "HardwareComposer::ComposerCallback::GetVsyncTime: Error "
- "while reading timestamp: %s",
- strerror(error));
- return ErrorStatus(error);
- }
-
- int64_t timestamp;
- ret = sscanf(data.data(), "VSYNC=%" PRIu64,
- reinterpret_cast<uint64_t*>(×tamp));
- if (ret < 0) {
- const int error = errno;
- ALOGE(
- "HardwareComposer::ComposerCallback::GetVsyncTime: Error while "
- "parsing timestamp: %s",
- strerror(error));
- return ErrorStatus(error);
- }
-
- return {timestamp};
-}
-
-HardwareComposer::ComposerCallback::DisplayInfo*
-HardwareComposer::ComposerCallback::GetDisplayInfo(hwc2_display_t display) {
- if (display == primary_display_.id) {
- return &primary_display_;
- } else if (external_display_ && display == external_display_->id) {
- return &(*external_display_);
- }
- return nullptr;
-}
-
-void Layer::Reset() {
- if (hardware_composer_layer_) {
- HWC::Error error =
- composer_->destroyLayer(display_params_.id, hardware_composer_layer_);
- if (error != HWC::Error::None &&
- (!ignore_bad_display_errors_on_destroy_ ||
- error != HWC::Error::BadDisplay)) {
- ALOGE("destroyLayer() failed for display %" PRIu64 ", layer %" PRIu64
- ". error: %s", display_params_.id, hardware_composer_layer_,
- error.to_string().c_str());
- }
- hardware_composer_layer_ = 0;
- }
-
- z_order_ = 0;
- blending_ = HWC::BlendMode::None;
- composition_type_ = HWC::Composition::Invalid;
- target_composition_type_ = composition_type_;
- source_ = EmptyVariant{};
- acquire_fence_.Close();
- surface_rect_functions_applied_ = false;
- pending_visibility_settings_ = true;
- cached_buffer_map_.clear();
- ignore_bad_display_errors_on_destroy_ = false;
-}
-
-Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
- const std::shared_ptr<DirectDisplaySurface>& surface,
- HWC::BlendMode blending, HWC::Composition composition_type,
- size_t z_order)
- : composer_(composer),
- display_params_(display_params),
- z_order_{z_order},
- blending_{blending},
- target_composition_type_{composition_type},
- source_{SourceSurface{surface}} {
- CommonLayerSetup();
-}
-
-Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
- const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
- HWC::Composition composition_type, size_t z_order)
- : composer_(composer),
- display_params_(display_params),
- z_order_{z_order},
- blending_{blending},
- target_composition_type_{composition_type},
- source_{SourceBuffer{buffer}} {
- CommonLayerSetup();
-}
-
-Layer::~Layer() { Reset(); }
-
-Layer::Layer(Layer&& other) noexcept { *this = std::move(other); }
-
-Layer& Layer::operator=(Layer&& other) noexcept {
- if (this != &other) {
- Reset();
- using std::swap;
- swap(composer_, other.composer_);
- swap(display_params_, other.display_params_);
- swap(hardware_composer_layer_, other.hardware_composer_layer_);
- swap(z_order_, other.z_order_);
- swap(blending_, other.blending_);
- swap(composition_type_, other.composition_type_);
- swap(target_composition_type_, other.target_composition_type_);
- swap(source_, other.source_);
- swap(acquire_fence_, other.acquire_fence_);
- swap(surface_rect_functions_applied_,
- other.surface_rect_functions_applied_);
- swap(pending_visibility_settings_, other.pending_visibility_settings_);
- swap(cached_buffer_map_, other.cached_buffer_map_);
- swap(ignore_bad_display_errors_on_destroy_,
- other.ignore_bad_display_errors_on_destroy_);
- }
- return *this;
-}
-
-void Layer::UpdateBuffer(const std::shared_ptr<IonBuffer>& buffer) {
- if (source_.is<SourceBuffer>())
- std::get<SourceBuffer>(source_) = {buffer};
-}
-
-void Layer::SetBlending(HWC::BlendMode blending) {
- if (blending_ != blending) {
- blending_ = blending;
- pending_visibility_settings_ = true;
- }
-}
-
-void Layer::SetZOrder(size_t z_order) {
- if (z_order_ != z_order) {
- z_order_ = z_order;
- pending_visibility_settings_ = true;
- }
-}
-
-IonBuffer* Layer::GetBuffer() {
- struct Visitor {
- IonBuffer* operator()(SourceSurface& source) { return source.GetBuffer(); }
- IonBuffer* operator()(SourceBuffer& source) { return source.GetBuffer(); }
- IonBuffer* operator()(EmptyVariant) { return nullptr; }
- };
- return source_.Visit(Visitor{});
-}
-
-void Layer::UpdateVisibilitySettings() {
- if (pending_visibility_settings_) {
- pending_visibility_settings_ = false;
-
- HWC::Error error;
-
- error = composer_->setLayerBlendMode(
- display_params_.id, hardware_composer_layer_,
- blending_.cast<Hwc2::IComposerClient::BlendMode>());
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
- error.to_string().c_str());
-
- error = composer_->setLayerZOrder(display_params_.id,
- hardware_composer_layer_, z_order_);
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting z_ order: %s",
- error.to_string().c_str());
- }
-}
-
-void Layer::UpdateLayerSettings() {
- HWC::Error error;
-
- UpdateVisibilitySettings();
-
- // TODO(eieio): Use surface attributes or some other mechanism to control
- // the layer display frame.
- error = composer_->setLayerDisplayFrame(
- display_params_.id, hardware_composer_layer_,
- {0, 0, display_params_.width, display_params_.height});
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting layer display frame: %s",
- error.to_string().c_str());
-
- error = composer_->setLayerVisibleRegion(
- display_params_.id, hardware_composer_layer_,
- {{0, 0, display_params_.width, display_params_.height}});
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting layer visible region: %s",
- error.to_string().c_str());
-
- error = composer_->setLayerPlaneAlpha(display_params_.id,
- hardware_composer_layer_, 1.0f);
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s",
- error.to_string().c_str());
-}
-
-void Layer::CommonLayerSetup() {
- HWC::Error error = composer_->createLayer(display_params_.id,
- &hardware_composer_layer_);
- ALOGE_IF(error != HWC::Error::None,
- "Layer::CommonLayerSetup: Failed to create layer on primary "
- "display: %s",
- error.to_string().c_str());
- UpdateLayerSettings();
-}
-
-bool Layer::CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id) {
- auto search = cached_buffer_map_.find(slot);
- if (search != cached_buffer_map_.end() && search->second == buffer_id)
- return true;
-
- // Assign or update the buffer slot.
- if (buffer_id >= 0)
- cached_buffer_map_[slot] = buffer_id;
- return false;
-}
-
-void Layer::Prepare() {
- int right, bottom, id;
- sp<GraphicBuffer> handle;
- std::size_t slot;
-
- // Acquire the next buffer according to the type of source.
- IfAnyOf<SourceSurface, SourceBuffer>::Call(&source_, [&](auto& source) {
- std::tie(right, bottom, id, handle, acquire_fence_, slot) =
- source.Acquire();
- });
-
- TRACE_FORMAT("Layer::Prepare|buffer_id=%d;slot=%zu|", id, slot);
-
- // Update any visibility (blending, z-order) changes that occurred since
- // last prepare.
- UpdateVisibilitySettings();
-
- // When a layer is first setup there may be some time before the first
- // buffer arrives. Setup the HWC layer as a solid color to stall for time
- // until the first buffer arrives. Once the first buffer arrives there will
- // always be a buffer for the frame even if it is old.
- if (!handle.get()) {
- if (composition_type_ == HWC::Composition::Invalid) {
- composition_type_ = HWC::Composition::SolidColor;
- composer_->setLayerCompositionType(
- display_params_.id, hardware_composer_layer_,
- composition_type_.cast<Hwc2::IComposerClient::Composition>());
- Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0};
- composer_->setLayerColor(display_params_.id, hardware_composer_layer_,
- layer_color);
- } else {
- // The composition type is already set. Nothing else to do until a
- // buffer arrives.
- }
- } else {
- if (composition_type_ != target_composition_type_) {
- composition_type_ = target_composition_type_;
- composer_->setLayerCompositionType(
- display_params_.id, hardware_composer_layer_,
- composition_type_.cast<Hwc2::IComposerClient::Composition>());
- }
-
- // See if the HWC cache already has this buffer.
- const bool cached = CheckAndUpdateCachedBuffer(slot, id);
- if (cached)
- handle = nullptr;
-
- HWC::Error error{HWC::Error::None};
- error =
- composer_->setLayerBuffer(display_params_.id, hardware_composer_layer_,
- slot, handle, acquire_fence_.Get());
-
- ALOGE_IF(error != HWC::Error::None,
- "Layer::Prepare: Error setting layer buffer: %s",
- error.to_string().c_str());
-
- if (!surface_rect_functions_applied_) {
- const float float_right = right;
- const float float_bottom = bottom;
- error = composer_->setLayerSourceCrop(display_params_.id,
- hardware_composer_layer_,
- {0, 0, float_right, float_bottom});
-
- ALOGE_IF(error != HWC::Error::None,
- "Layer::Prepare: Error setting layer source crop: %s",
- error.to_string().c_str());
-
- surface_rect_functions_applied_ = true;
- }
- }
-}
-
-void Layer::Finish(int release_fence_fd) {
- IfAnyOf<SourceSurface, SourceBuffer>::Call(
- &source_, [release_fence_fd](auto& source) {
- source.Finish(LocalHandle(release_fence_fd));
- });
-}
-
-void Layer::Drop() { acquire_fence_.Close(); }
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
deleted file mode 100644
index bfce10b..0000000
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ /dev/null
@@ -1,577 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_DISPLAYD_HARDWARE_COMPOSER_H_
-#define ANDROID_DVR_SERVICES_DISPLAYD_HARDWARE_COMPOSER_H_
-
-#include <ui/GraphicBuffer.h>
-#include "DisplayHardware/ComposerHal.h"
-#include "hwc_types.h"
-
-#include <dvr/dvr_shared_buffers.h>
-#include <hardware/gralloc.h>
-#include <log/log.h>
-
-#include <array>
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-#include <optional>
-#include <thread>
-#include <tuple>
-#include <vector>
-
-#include <dvr/dvr_config.h>
-#include <dvr/dvr_vsync.h>
-#include <pdx/file_handle.h>
-#include <pdx/rpc/variant.h>
-#include <private/dvr/shared_buffer_helpers.h>
-#include <private/dvr/vsync_service.h>
-
-#include "DisplayHardware/DisplayIdentification.h"
-#include "acquired_buffer.h"
-#include "display_surface.h"
-
-// Hardware composer HAL doesn't define HWC_TRANSFORM_NONE as of this writing.
-#ifndef HWC_TRANSFORM_NONE
-#define HWC_TRANSFORM_NONE static_cast<hwc_transform_t>(0)
-#endif
-
-namespace android {
-namespace dvr {
-
-// Basic display metrics for physical displays.
-struct DisplayParams {
- hwc2_display_t id;
- bool is_primary;
-
- int width;
- int height;
-
- struct {
- int x;
- int y;
- } dpi;
-
- int vsync_period_ns;
-};
-
-// Layer represents the connection between a hardware composer layer and the
-// source supplying buffers for the layer's contents.
-class Layer {
- public:
- Layer() = default;
-
- // Sets up the layer to use a display surface as its content source. The Layer
- // automatically handles ACQUIRE/RELEASE phases for the surface's buffer train
- // every frame.
- //
- // |composer| The composer instance.
- // |display_params| Info about the display to use.
- // |blending| receives HWC_BLENDING_* values.
- // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
- // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
- // |index| is the index of this surface in the DirectDisplaySurface array.
- Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
- const std::shared_ptr<DirectDisplaySurface>& surface,
- HWC::BlendMode blending, HWC::Composition composition_type,
- size_t z_order);
-
- // Sets up the layer to use a direct buffer as its content source. No special
- // handling of the buffer is performed; responsibility for updating or
- // changing the buffer each frame is on the caller.
- //
- // |composer| The composer instance.
- // |display_params| Info about the display to use.
- // |blending| receives HWC_BLENDING_* values.
- // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
- // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
- Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
- const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
- HWC::Composition composition_type, size_t z_order);
-
- Layer(Layer&&) noexcept;
- Layer& operator=(Layer&&) noexcept;
-
- ~Layer();
-
- // Releases any shared pointers and fence handles held by this instance.
- void Reset();
-
- // Layers that use a direct IonBuffer should call this each frame to update
- // which buffer will be used for the next PostLayers.
- void UpdateBuffer(const std::shared_ptr<IonBuffer>& buffer);
-
- // Sets up the hardware composer layer for the next frame. When the layer is
- // associated with a display surface, this method automatically ACQUIRES a new
- // buffer if one is available.
- void Prepare();
-
- // After calling prepare, if this frame is to be dropped instead of passing
- // along to the HWC, call Drop to close the contained fence(s).
- void Drop();
-
- // Performs fence bookkeeping after the frame has been posted to hardware
- // composer.
- void Finish(int release_fence_fd);
-
- // Sets the blending for the layer. |blending| receives HWC_BLENDING_* values.
- void SetBlending(HWC::BlendMode blending);
-
- // Sets the z-order of this layer
- void SetZOrder(size_t z_order);
-
- // Gets the current IonBuffer associated with this layer. Ownership of the
- // buffer DOES NOT pass to the caller and the pointer is not guaranteed to
- // remain valid across calls to Layer::Setup(), Layer::Prepare(), or
- // Layer::Reset(). YOU HAVE BEEN WARNED.
- IonBuffer* GetBuffer();
-
- HWC::Composition GetCompositionType() const { return composition_type_; }
- HWC::Layer GetLayerHandle() const { return hardware_composer_layer_; }
- bool IsLayerSetup() const { return !source_.empty(); }
-
- int GetSurfaceId() const {
- int surface_id = -1;
- pdx::rpc::IfAnyOf<SourceSurface>::Call(
- &source_, [&surface_id](const SourceSurface& surface_source) {
- surface_id = surface_source.GetSurfaceId();
- });
- return surface_id;
- }
-
- int GetBufferId() const {
- int buffer_id = -1;
- pdx::rpc::IfAnyOf<SourceSurface>::Call(
- &source_, [&buffer_id](const SourceSurface& surface_source) {
- buffer_id = surface_source.GetBufferId();
- });
- return buffer_id;
- }
-
- // Compares Layers by surface id.
- bool operator<(const Layer& other) const {
- return GetSurfaceId() < other.GetSurfaceId();
- }
- bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; }
-
- void IgnoreBadDisplayErrorsOnDestroy(bool ignore) {
- ignore_bad_display_errors_on_destroy_ = ignore;
- }
-
- private:
- void CommonLayerSetup();
-
- // Applies all of the settings to this layer using the hwc functions
- void UpdateLayerSettings();
-
- // Applies visibility settings that may have changed.
- void UpdateVisibilitySettings();
-
- // Checks whether the buffer, given by id, is associated with the given slot
- // in the HWC buffer cache. If the slot is not associated with the given
- // buffer the cache is updated to establish the association and the buffer
- // should be sent to HWC using setLayerBuffer. Returns true if the association
- // was already established, false if not. A buffer_id of -1 is never
- // associated and always returns false.
- bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id);
-
- // Composer instance.
- Hwc2::Composer* composer_ = nullptr;
-
- // Parameters of the display to use for this layer.
- DisplayParams display_params_;
-
- // The hardware composer layer and metrics to use during the prepare cycle.
- hwc2_layer_t hardware_composer_layer_ = 0;
-
- // Layer properties used to setup the hardware composer layer during the
- // Prepare phase.
- size_t z_order_ = 0;
- HWC::BlendMode blending_ = HWC::BlendMode::None;
- HWC::Composition composition_type_ = HWC::Composition::Invalid;
- HWC::Composition target_composition_type_ = HWC::Composition::Device;
-
- // State when the layer is connected to a surface. Provides the same interface
- // as SourceBuffer to simplify internal use by Layer.
- struct SourceSurface {
- std::shared_ptr<DirectDisplaySurface> surface;
- AcquiredBuffer acquired_buffer;
- pdx::LocalHandle release_fence;
-
- explicit SourceSurface(const std::shared_ptr<DirectDisplaySurface>& surface)
- : surface(surface) {}
-
- // Attempts to acquire a new buffer from the surface and return a tuple with
- // width, height, buffer handle, and fence. If a new buffer is not available
- // the previous buffer is returned or an empty value if no buffer has ever
- // been posted. When a new buffer is acquired the previous buffer's release
- // fence is passed out automatically.
- std::tuple<int, int, int, sp<GraphicBuffer>, pdx::LocalHandle, std::size_t>
- Acquire() {
- if (surface->IsBufferAvailable()) {
- acquired_buffer.Release(std::move(release_fence));
- acquired_buffer = surface->AcquireCurrentBuffer();
- ATRACE_ASYNC_END("BufferPost", acquired_buffer.buffer()->id());
- }
- if (!acquired_buffer.IsEmpty()) {
- return std::make_tuple(
- acquired_buffer.buffer()->width(),
- acquired_buffer.buffer()->height(), acquired_buffer.buffer()->id(),
- acquired_buffer.buffer()->buffer()->buffer(),
- acquired_buffer.ClaimAcquireFence(), acquired_buffer.slot());
- } else {
- return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0);
- }
- }
-
- void Finish(pdx::LocalHandle fence) { release_fence = std::move(fence); }
-
- // Gets a pointer to the current acquired buffer or returns nullptr if there
- // isn't one.
- IonBuffer* GetBuffer() {
- if (acquired_buffer.IsAvailable())
- return acquired_buffer.buffer()->buffer();
- else
- return nullptr;
- }
-
- // Returns the surface id of the surface.
- int GetSurfaceId() const { return surface->surface_id(); }
-
- // Returns the buffer id for the current buffer.
- int GetBufferId() const {
- if (acquired_buffer.IsAvailable())
- return acquired_buffer.buffer()->id();
- else
- return -1;
- }
- };
-
- // State when the layer is connected to a buffer. Provides the same interface
- // as SourceSurface to simplify internal use by Layer.
- struct SourceBuffer {
- std::shared_ptr<IonBuffer> buffer;
-
- std::tuple<int, int, int, sp<GraphicBuffer>, pdx::LocalHandle, std::size_t>
- Acquire() {
- if (buffer)
- return std::make_tuple(buffer->width(), buffer->height(), -1,
- buffer->buffer(), pdx::LocalHandle{}, 0);
- else
- return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0);
- }
-
- void Finish(pdx::LocalHandle /*fence*/) {}
-
- IonBuffer* GetBuffer() { return buffer.get(); }
-
- int GetSurfaceId() const { return -1; }
- int GetBufferId() const { return -1; }
- };
-
- // The underlying hardware composer layer is supplied buffers either from a
- // surface buffer train or from a buffer directly.
- pdx::rpc::Variant<SourceSurface, SourceBuffer> source_;
-
- pdx::LocalHandle acquire_fence_;
- bool surface_rect_functions_applied_ = false;
- bool pending_visibility_settings_ = true;
-
- // Map of buffer slot assignments that have already been established with HWC:
- // slot -> buffer_id. When this map contains a matching slot and buffer_id the
- // buffer argument to setLayerBuffer may be nullptr to avoid the cost of
- // importing a buffer HWC already knows about.
- std::map<std::size_t, int> cached_buffer_map_;
-
- // When calling destroyLayer() on an external display that's been removed we
- // typically get HWC2_ERROR_BAD_DISPLAY errors. If
- // ignore_bad_display_errors_on_destroy_ is true, don't log the bad display
- // errors, since they're expected.
- bool ignore_bad_display_errors_on_destroy_ = false;
-
- Layer(const Layer&) = delete;
- void operator=(const Layer&) = delete;
-};
-
-// HardwareComposer encapsulates the hardware composer HAL, exposing a
-// simplified API to post buffers to the display.
-//
-// HardwareComposer is accessed by both the vr flinger dispatcher thread and the
-// surface flinger main thread, in addition to internally running a separate
-// thread for compositing/EDS and posting layers to the HAL. When changing how
-// variables are used or adding new state think carefully about which threads
-// will access the state and whether it needs to be synchronized.
-class HardwareComposer {
- public:
- using RequestDisplayCallback = std::function<void(bool)>;
-
- HardwareComposer();
- ~HardwareComposer();
-
- bool Initialize(Hwc2::Composer* composer,
- hwc2_display_t primary_display_id,
- RequestDisplayCallback request_display_callback);
-
- bool IsInitialized() const { return initialized_; }
-
- // Start the post thread if there's work to do (i.e. visible layers). This
- // should only be called from surface flinger's main thread.
- void Enable();
- // Pause the post thread, blocking until the post thread has signaled that
- // it's paused. This should only be called from surface flinger's main thread.
- void Disable();
-
- // Called on a binder thread.
- void OnBootFinished();
-
- std::string Dump();
-
- const DisplayParams& GetPrimaryDisplayParams() const {
- return primary_display_;
- }
-
- // Sets the display surfaces to compose the hardware layer stack.
- void SetDisplaySurfaces(
- std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces);
-
- int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer);
- void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
-
- // Gets the edid data for the current active display (internal or external)
- DisplayIdentificationData GetCurrentDisplayIdentificationData() {
- return display_identification_data_;
- }
-
- // Gets the edid port for the current active display (internal or external)
- uint8_t GetCurrentDisplayPort() { return display_port_; }
-
- private:
- DisplayParams GetDisplayParams(Hwc2::Composer* composer,
- hwc2_display_t display, bool is_primary);
-
- // Turn display vsync on/off. Returns true on success, false on failure.
- bool EnableVsync(const DisplayParams& display, bool enabled);
- // Turn display power on/off. Returns true on success, false on failure.
- bool SetPowerMode(const DisplayParams& display, bool active);
- // Convenience function to turn a display on/off. Turns both power and vsync
- // on/off. Returns true on success, false on failure.
- bool EnableDisplay(const DisplayParams& display, bool enabled);
-
- class VsyncService : public BnVsyncService {
- public:
- status_t registerCallback(const sp<IVsyncCallback> callback) override;
- status_t unregisterCallback(const sp<IVsyncCallback> callback) override;
- void OnVsync(int64_t vsync_timestamp);
- private:
- std::vector<sp<IVsyncCallback>>::const_iterator FindCallback(
- const sp<IVsyncCallback>& callback) const;
- std::mutex mutex_;
- std::vector<sp<IVsyncCallback>> callbacks_;
- };
-
- class ComposerCallback : public Hwc2::IComposerCallback {
- public:
- ComposerCallback() = default;
- hardware::Return<void> onHotplug(Hwc2::Display display,
- Connection conn) override;
- hardware::Return<void> onRefresh(Hwc2::Display display) override;
- hardware::Return<void> onVsync(Hwc2::Display display,
- int64_t timestamp) override;
- hardware::Return<void> onVsync_2_4(
- Hwc2::Display display, int64_t timestamp,
- Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override;
- hardware::Return<void> onVsyncPeriodTimingChanged(
- Hwc2::Display display,
- const Hwc2::VsyncPeriodChangeTimeline& updatedTimeline) override;
- hardware::Return<void> onSeamlessPossible(Hwc2::Display display) override;
-
- bool GotFirstHotplug() { return got_first_hotplug_; }
- void SetVsyncService(const sp<VsyncService>& vsync_service);
-
- struct Displays {
- hwc2_display_t primary_display = 0;
- std::optional<hwc2_display_t> external_display;
- bool external_display_was_hotplugged = false;
- };
-
- Displays GetDisplays();
- pdx::Status<int64_t> GetVsyncTime(hwc2_display_t display);
-
- private:
- struct DisplayInfo {
- hwc2_display_t id = 0;
- pdx::LocalHandle driver_vsync_event_fd;
- int64_t callback_vsync_timestamp{0};
- };
-
- DisplayInfo* GetDisplayInfo(hwc2_display_t display);
-
- std::mutex mutex_;
-
- bool got_first_hotplug_ = false;
- DisplayInfo primary_display_;
- std::optional<DisplayInfo> external_display_;
- bool external_display_was_hotplugged_ = false;
- sp<VsyncService> vsync_service_;
- };
-
- HWC::Error Validate(hwc2_display_t display);
- HWC::Error Present(hwc2_display_t display);
-
- void PostLayers(hwc2_display_t display);
- void PostThread();
-
- // The post thread has two controlling states:
- // 1. Idle: no work to do (no visible surfaces).
- // 2. Suspended: explicitly halted (system is not in VR mode).
- // When either #1 or #2 is true then the post thread is quiescent, otherwise
- // it is active.
- using PostThreadStateType = uint32_t;
- struct PostThreadState {
- enum : PostThreadStateType {
- Active = 0,
- Idle = (1 << 0),
- Suspended = (1 << 1),
- Quit = (1 << 2),
- };
- };
-
- void UpdatePostThreadState(uint32_t state, bool suspend);
-
- // Blocks until either event_fd becomes readable, or we're interrupted by a
- // control thread, or timeout_ms is reached before any events occur. Any
- // errors are returned as negative errno values, with -ETIMEDOUT returned in
- // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be
- // returned.
- int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd,
- int requested_events, int timeout_ms);
-
- // WaitForPredictedVSync and SleepUntil are blocking calls made on the post
- // thread that can be interrupted by a control thread. If interrupted, these
- // calls return kPostThreadInterrupted.
- int ReadWaitPPState();
- pdx::Status<int64_t> WaitForPredictedVSync();
- int SleepUntil(int64_t wakeup_timestamp);
-
- // Initialize any newly connected displays, and set target_display_ to the
- // display we should render to. Returns true if target_display_
- // changed. Called only from the post thread.
- bool UpdateTargetDisplay();
-
- // Reconfigures the layer stack if the display surfaces changed since the last
- // frame. Called only from the post thread.
- void UpdateLayerConfig();
-
- // Called on the post thread to create the Composer instance.
- void CreateComposer();
-
- // Called on the post thread when the post thread is resumed.
- void OnPostThreadResumed();
- // Called on the post thread when the post thread is paused or quits.
- void OnPostThreadPaused();
-
- // Use post_thread_wait_ to wait for a specific condition, specified by pred.
- // timeout_sec < 0 means wait indefinitely, otherwise it specifies the timeout
- // in seconds.
- // The lock must be held when this function is called.
- // Returns true if the wait was interrupted because the post thread was asked
- // to quit.
- bool PostThreadCondWait(std::unique_lock<std::mutex>& lock,
- int timeout_sec,
- const std::function<bool()>& pred);
-
- // Map the given shared memory buffer to our broadcast ring to track updates
- // to the config parameters.
- int MapConfigBuffer(IonBuffer& ion_buffer);
- void ConfigBufferDeleted();
- // Poll for config udpates.
- void UpdateConfigBuffer();
-
- bool initialized_;
- bool is_standalone_device_;
-
- std::unique_ptr<Hwc2::Composer> composer_;
- sp<ComposerCallback> composer_callback_;
- RequestDisplayCallback request_display_callback_;
-
- DisplayParams primary_display_;
- std::optional<DisplayParams> external_display_;
- DisplayParams* target_display_ = &primary_display_;
-
- // The list of surfaces we should draw. Set by the display service when
- // DirectSurfaces are added, removed, or change visibility. Written by the
- // message dispatch thread and read by the post thread.
- std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces_;
- // Set to true by the dispatch thread whenever surfaces_ changes. Set to false
- // by the post thread when the new list of surfaces is processed.
- bool surfaces_changed_ = false;
-
- std::vector<std::shared_ptr<DirectDisplaySurface>> current_surfaces_;
-
- // Layer set for handling buffer flow into hardware composer layers. This
- // vector must be sorted by surface_id in ascending order.
- std::vector<Layer> layers_;
-
- // The layer posting thread. This thread wakes up a short time before vsync to
- // hand buffers to hardware composer.
- std::thread post_thread_;
-
- // Post thread state machine and synchronization primitives.
- PostThreadStateType post_thread_state_{PostThreadState::Idle |
- PostThreadState::Suspended};
- std::atomic<bool> post_thread_quiescent_{true};
- bool post_thread_resumed_{false};
- pdx::LocalHandle post_thread_event_fd_;
- std::mutex post_thread_mutex_;
- std::condition_variable post_thread_wait_;
- std::condition_variable post_thread_ready_;
-
- // When boot is finished this will be set to true and the post thread will be
- // notified via post_thread_wait_.
- bool boot_finished_ = false;
-
- // VSync sleep timerfd.
- pdx::LocalHandle vsync_sleep_timer_fd_;
-
- // The timestamp of the last vsync.
- int64_t last_vsync_timestamp_ = 0;
-
- // The number of vsync intervals to predict since the last vsync.
- int vsync_prediction_interval_ = 1;
-
- // Vsync count since display on.
- uint32_t vsync_count_ = 0;
-
- // Counter tracking the number of skipped frames.
- int frame_skip_count_ = 0;
-
- // Fd array for tracking retire fences that are returned by hwc. This allows
- // us to detect when the display driver begins queuing frames.
- std::vector<pdx::LocalHandle> retire_fence_fds_;
-
- // If we are publishing vsync data, we will put it here.
- std::unique_ptr<CPUMappedBroadcastRing<DvrVsyncRing>> vsync_ring_;
-
- // Broadcast ring for receiving config data from the DisplayManager.
- DvrConfigRing shared_config_ring_;
- uint32_t shared_config_ring_sequence_{0};
- // Config buffer for reading from the post thread.
- DvrConfig post_thread_config_;
- std::mutex shared_config_mutex_;
-
- bool vsync_trace_parity_ = false;
- sp<VsyncService> vsync_service_;
-
- // Edid section.
- void UpdateEdidData(Hwc2::Composer* composer, hwc2_display_t hw_id);
- DisplayIdentificationData display_identification_data_;
- uint8_t display_port_;
-
- static constexpr int kPostThreadInterrupted = 1;
-
- HardwareComposer(const HardwareComposer&) = delete;
- void operator=(const HardwareComposer&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_SERVICES_DISPLAYD_HARDWARE_COMPOSER_H_
diff --git a/libs/vr/libvrflinger/hwc_types.h b/libs/vr/libvrflinger/hwc_types.h
deleted file mode 100644
index 8b5c3b3..0000000
--- a/libs/vr/libvrflinger/hwc_types.h
+++ /dev/null
@@ -1,307 +0,0 @@
-#ifndef ANDROID_LIBVRFLINGER_HWCTYPES_H
-#define ANDROID_LIBVRFLINGER_HWCTYPES_H
-
-// General HWC type support. Hardware composer type support is a bit of a mess
-// between HWC1, HWC2 C/C++11, and HIDL types. Particularly bothersome is the
-// use of enum classes, which make analogous types between versions much
-// harder to deal with in a uniform way.
-//
-// These utilities help address some of these pains by providing a type-safe,
-// flexible interface to translate between different type spaces.
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include <string>
-#include <type_traits>
-
-namespace HWC {
-
-// Value types derived from HWC HAL types. Some of these are stand-alone,
-// while others are also wrapped in translator classes below.
-using ColorMode = int32_t; // android_color_mode_t;
-using Config = hwc2_config_t;
-using ColorTransform =
- std::underlying_type<android_color_transform_t>::type; // int32_t;
-using Dataspace = std::underlying_type<android_dataspace_t>::type; // int32_t;
-using DisplayId = hwc2_display_t;
-using DisplayRequest = std::underlying_type<HWC2::DisplayRequest>::type;
-using Hdr = std::underlying_type<android_hdr_t>::type; // int32_t;
-using Layer = hwc2_layer_t;
-using PixelFormat =
- std::underlying_type<android_pixel_format_t>::type; // int32_t;
-
-// Type traits and casting utilities.
-
-// SFINAE utility to evaluate type expressions.
-template <typename...>
-using TestTypeExpression = void;
-
-// Traits type to determine the underlying type of an enum, integer,
-// or wrapper class.
-template <typename T, typename = typename std::is_enum<T>::type,
- typename = typename std::is_integral<T>::type, typename = void>
-struct UnderlyingType {
- using Type = T;
-};
-// Partial specialization that matches enum types. Captures the underlying type
-// of the enum in member type Type.
-template <typename T>
-struct UnderlyingType<T, std::true_type, std::false_type> {
- using Type = typename std::underlying_type<T>::type;
-};
-// Partial specialization that matches integral types. Captures the type of the
-// integer in member type Type.
-template <typename T>
-struct UnderlyingType<T, std::false_type, std::true_type> {
- using Type = T;
-};
-// Partial specialization that matches the wrapper types below. Captures
-// wrapper member type ValueType in member type Type.
-template <typename T>
-struct UnderlyingType<T, std::false_type, std::false_type,
- TestTypeExpression<typename T::ValueType>> {
- using Type = typename T::ValueType;
-};
-
-// Enable if T is an enum with underlying type U.
-template <typename T, typename U, typename ReturnType = void>
-using EnableIfMatchingEnum = typename std::enable_if<
- std::is_enum<T>::value &&
- std::is_same<U, typename UnderlyingType<T>::Type>::value,
- ReturnType>::type;
-
-// Enable if T and U are the same size/alignment and have the same underlying
-// type. Handles enum, integral, and wrapper classes below.
-template <typename T, typename U, typename Return = void>
-using EnableIfSafeCast = typename std::enable_if<
- sizeof(T) == sizeof(U) && alignof(T) == alignof(U) &&
- std::is_same<typename UnderlyingType<T>::Type,
- typename UnderlyingType<U>::Type>::value,
- Return>::type;
-
-// Safely cast between std::vectors of matching enum/integer/wraper types.
-// Normally this is not possible with pendantic compiler type checks. However,
-// given the same size, alignment, and underlying type this is safe due to
-// allocator requirements and array-like element access guarantees.
-template <typename T, typename U>
-EnableIfSafeCast<T, U, std::vector<T>*> VectorCast(std::vector<U>* in) {
- return reinterpret_cast<std::vector<T>*>(in);
-}
-
-// Translator classes that wrap specific HWC types to make translating
-// between different types (especially enum class) in code cleaner.
-
-// Base type for the enum wrappers below. This type provides type definitions
-// and implicit conversion logic common to each wrapper type.
-template <typename EnumType>
-struct Wrapper {
- // Alias type of this instantiantion of Wrapper. Useful for inheriting
- // constructors in subclasses via "using Base::Base;" statements.
- using Base = Wrapper<EnumType>;
-
- // The enum type wrapped by this instantiation of Wrapper.
- using BaseType = EnumType;
-
- // The underlying type of the base enum type.
- using ValueType = typename UnderlyingType<BaseType>::Type;
-
- // A default constructor is not defined here. Subclasses should define one
- // as appropriate to define the correct inital value for the enum type.
-
- // Default copy constructor.
- Wrapper(const Wrapper&) = default;
-
- // Implicit conversion from ValueType.
- // NOLINTNEXTLINE(google-explicit-constructor)
- Wrapper(ValueType value) : value(value) {}
-
- // Implicit conversion from BaseType.
- // NOLINTNEXTLINE(google-explicit-constructor)
- Wrapper(BaseType value) : value(static_cast<ValueType>(value)) {}
-
- // Implicit conversion from an enum type of the same underlying type.
- template <typename T, typename = EnableIfMatchingEnum<T, ValueType>>
- // NOLINTNEXTLINE(google-explicit-constructor)
- Wrapper(const T& value) : value(static_cast<ValueType>(value)) {}
-
- // Implicit conversion to BaseType.
- // NOLINTNEXTLINE(google-explicit-constructor)
- operator BaseType() const { return static_cast<BaseType>(value); }
-
- // Implicit conversion to ValueType.
- // NOLINTNEXTLINE(google-explicit-constructor)
- operator ValueType() const { return value; }
-
- template <typename T, typename = EnableIfMatchingEnum<T, ValueType>>
- T cast() const {
- return static_cast<T>(value);
- }
-
- // Converts to string using HWC2 stringification of BaseType.
- std::string to_string() const {
- return HWC2::to_string(static_cast<BaseType>(value));
- }
-
- bool operator!=(const Wrapper& other) const { return value != other.value; }
- bool operator!=(ValueType other_value) const { return value != other_value; }
- bool operator!=(BaseType other_value) const {
- return static_cast<BaseType>(value) != other_value;
- }
- bool operator==(const Wrapper& other) const { return value == other.value; }
- bool operator==(ValueType other_value) const { return value == other_value; }
- bool operator==(BaseType other_value) const {
- return static_cast<BaseType>(value) == other_value;
- }
-
- ValueType value;
-};
-
-struct Attribute final : public Wrapper<HWC2::Attribute> {
- enum : ValueType {
- Invalid = HWC2_ATTRIBUTE_INVALID,
- Width = HWC2_ATTRIBUTE_WIDTH,
- Height = HWC2_ATTRIBUTE_HEIGHT,
- VsyncPeriod = HWC2_ATTRIBUTE_VSYNC_PERIOD,
- DpiX = HWC2_ATTRIBUTE_DPI_X,
- DpiY = HWC2_ATTRIBUTE_DPI_Y,
- };
-
- Attribute() : Base(Invalid) {}
- using Base::Base;
-};
-
-struct BlendMode final : public Wrapper<HWC2::BlendMode> {
- enum : ValueType {
- Invalid = HWC2_BLEND_MODE_INVALID,
- None = HWC2_BLEND_MODE_NONE,
- Premultiplied = HWC2_BLEND_MODE_PREMULTIPLIED,
- Coverage = HWC2_BLEND_MODE_COVERAGE,
- };
-
- BlendMode() : Base(Invalid) {}
- using Base::Base;
-};
-
-struct Composition final : public Wrapper<HWC2::Composition> {
- enum : ValueType {
- Invalid = HWC2_COMPOSITION_INVALID,
- Client = HWC2_COMPOSITION_CLIENT,
- Device = HWC2_COMPOSITION_DEVICE,
- SolidColor = HWC2_COMPOSITION_SOLID_COLOR,
- Cursor = HWC2_COMPOSITION_CURSOR,
- Sideband = HWC2_COMPOSITION_SIDEBAND,
- };
-
- Composition() : Base(Invalid) {}
- using Base::Base;
-};
-
-struct DisplayType final : public Wrapper<HWC2::DisplayType> {
- enum : ValueType {
- Invalid = HWC2_DISPLAY_TYPE_INVALID,
- Physical = HWC2_DISPLAY_TYPE_PHYSICAL,
- Virtual = HWC2_DISPLAY_TYPE_VIRTUAL,
- };
-
- DisplayType() : Base(Invalid) {}
- using Base::Base;
-};
-
-struct Error final : public Wrapper<HWC2::Error> {
- enum : ValueType {
- None = HWC2_ERROR_NONE,
- BadConfig = HWC2_ERROR_BAD_CONFIG,
- BadDisplay = HWC2_ERROR_BAD_DISPLAY,
- BadLayer = HWC2_ERROR_BAD_LAYER,
- BadParameter = HWC2_ERROR_BAD_PARAMETER,
- HasChanges = HWC2_ERROR_HAS_CHANGES,
- NoResources = HWC2_ERROR_NO_RESOURCES,
- NotValidated = HWC2_ERROR_NOT_VALIDATED,
- Unsupported = HWC2_ERROR_UNSUPPORTED,
- };
-
- Error() : Base(None) {}
- using Base::Base;
-};
-
-struct LayerRequest final : public Wrapper<HWC2::LayerRequest> {
- enum : ValueType {
- ClearClientTarget = HWC2_LAYER_REQUEST_CLEAR_CLIENT_TARGET,
- };
-
- LayerRequest() : Base(0) {}
- using Base::Base;
-};
-
-struct PowerMode final : public Wrapper<HWC2::PowerMode> {
- enum : ValueType {
- Off = HWC2_POWER_MODE_OFF,
- DozeSuspend = HWC2_POWER_MODE_DOZE_SUSPEND,
- Doze = HWC2_POWER_MODE_DOZE,
- On = HWC2_POWER_MODE_ON,
- };
-
- PowerMode() : Base(Off) {}
- using Base::Base;
-};
-
-struct Transform final : public Wrapper<HWC2::Transform> {
- enum : ValueType {
- None = 0,
- FlipH = HWC_TRANSFORM_FLIP_H,
- FlipV = HWC_TRANSFORM_FLIP_V,
- Rotate90 = HWC_TRANSFORM_ROT_90,
- Rotate180 = HWC_TRANSFORM_ROT_180,
- Rotate270 = HWC_TRANSFORM_ROT_270,
- FlipHRotate90 = HWC_TRANSFORM_FLIP_H_ROT_90,
- FlipVRotate90 = HWC_TRANSFORM_FLIP_V_ROT_90,
- };
-
- Transform() : Base(None) {}
- using Base::Base;
-};
-
-struct Vsync final : public Wrapper<HWC2::Vsync> {
- enum : ValueType {
- Invalid = HWC2_VSYNC_INVALID,
- Enable = HWC2_VSYNC_ENABLE,
- Disable = HWC2_VSYNC_DISABLE,
- };
-
- Vsync() : Base(Invalid) {}
- using Base::Base;
-};
-
-// Utility color type.
-struct Color final {
- Color(const Color&) = default;
- Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a) {}
- // NOLINTNEXTLINE(google-explicit-constructor)
- Color(hwc_color_t color) : r(color.r), g(color.g), b(color.b), a(color.a) {}
-
- // NOLINTNEXTLINE(google-explicit-constructor)
- operator hwc_color_t() const { return {r, g, b, a}; }
-
- uint8_t r __attribute__((aligned(1)));
- uint8_t g __attribute__((aligned(1)));
- uint8_t b __attribute__((aligned(1)));
- uint8_t a __attribute__((aligned(1)));
-};
-
-// Utility rectangle type.
-struct Rect final {
- // TODO(eieio): Implicit conversion to/from Android rect types.
-
- int32_t left __attribute__((aligned(4)));
- int32_t top __attribute__((aligned(4)));
- int32_t right __attribute__((aligned(4)));
- int32_t bottom __attribute__((aligned(4)));
-};
-
-} // namespace HWC
-
-#endif // ANDROID_LIBVRFLINGER_HWCTYPES_H
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
deleted file mode 100644
index ae52076..0000000
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef ANDROID_DVR_VR_FLINGER_H_
-#define ANDROID_DVR_VR_FLINGER_H_
-
-#include <thread>
-#include <memory>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include <pdx/service_dispatcher.h>
-#include <vr/vr_manager/vr_manager.h>
-
-namespace android {
-
-namespace Hwc2 {
-class Composer;
-} // namespace Hwc2
-
-namespace dvr {
-
-class DisplayService;
-
-class VrFlinger {
- public:
- using RequestDisplayCallback = std::function<void(bool)>;
- static std::unique_ptr<VrFlinger> Create(
- Hwc2::Composer* hidl,
- hwc2_display_t primary_display_id,
- RequestDisplayCallback request_display_callback);
- ~VrFlinger();
-
- // These functions are all called on surface flinger's main thread.
- void OnBootFinished();
- void GrantDisplayOwnership();
- void SeizeDisplayOwnership();
-
- // dump all vr flinger state.
- std::string Dump();
-
- private:
- VrFlinger();
- bool Init(Hwc2::Composer* hidl,
- hwc2_display_t primary_display_id,
- RequestDisplayCallback request_display_callback);
-
- // Needs to be a separate class for binder's ref counting
- class PersistentVrStateCallback : public BnPersistentVrStateCallbacks {
- public:
- explicit PersistentVrStateCallback(
- RequestDisplayCallback request_display_callback)
- : request_display_callback_(request_display_callback) {}
- void onPersistentVrStateChanged(bool enabled) override;
- private:
- RequestDisplayCallback request_display_callback_;
- };
-
- std::thread dispatcher_thread_;
- std::unique_ptr<android::pdx::ServiceDispatcher> dispatcher_;
- std::shared_ptr<android::dvr::DisplayService> display_service_;
- sp<PersistentVrStateCallback> persistent_vr_state_callback_;
- RequestDisplayCallback request_display_callback_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_VR_FLINGER_H_
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
deleted file mode 100644
index 095f556..0000000
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ /dev/null
@@ -1,47 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-shared_libs = [
- "android.hardware.configstore-utils",
- "android.hardware.configstore@1.0",
- "libbinder",
- "libbufferhubqueue",
- "libcutils",
- "libgui",
- "libhidlbase",
- "liblog",
- "libui",
- "libutils",
- "libnativewindow",
- "libpdx_default_transport",
- "libSurfaceFlingerProp",
-]
-
-static_libs = [
- "libdisplay",
-]
-
-cc_test {
- srcs: ["vrflinger_test.cpp"],
- // See go/apct-presubmit for documentation on how this .filter file is used
- // by Android's automated testing infrastructure for test filtering.
- data: ["vrflinger_test.filter"],
- static_libs: static_libs,
- shared_libs: shared_libs,
- cflags: [
- "-DLOG_TAG=\"VrFlingerTest\"",
- "-DTRACE=0",
- "-O0",
- "-g",
- "-Wall",
- "-Werror",
- ],
- header_libs: ["libsurfaceflinger_headers"],
- name: "vrflinger_test",
-}
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
deleted file mode 100644
index ac44f74..0000000
--- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-#include <SurfaceFlingerProperties.h>
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <android/hardware/configstore/1.1/types.h>
-#include <android/hardware_buffer.h>
-#include <binder/IServiceManager.h>
-#include <binder/Parcel.h>
-#include <binder/ProcessState.h>
-#include <configstore/Utils.h>
-#include <cutils/properties.h>
-#include <gtest/gtest.h>
-#include <gui/ISurfaceComposer.h>
-#include <log/log.h>
-#include <utils/StrongPointer.h>
-
-#include <chrono>
-#include <memory>
-#include <mutex>
-#include <optional>
-#include <thread>
-
-#include <private/dvr/display_client.h>
-
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-using android::dvr::display::DisplayClient;
-using android::dvr::display::Surface;
-using android::dvr::display::SurfaceAttribute;
-using android::dvr::display::SurfaceAttributeValue;
-
-namespace android {
-namespace dvr {
-
-// The transaction code for asking surface flinger if vr flinger is active. This
-// is done as a hidden api since it's only used for tests. See the "case 1028"
-// block in SurfaceFlinger::onTransact() in SurfaceFlinger.cpp.
-constexpr uint32_t kIsVrFlingerActiveTransactionCode = 1028;
-
-// The maximum amount of time to give vr flinger to activate/deactivate. If the
-// switch hasn't completed in this amount of time, the test will fail.
-constexpr auto kVrFlingerSwitchMaxTime = std::chrono::seconds(1);
-
-// How long to wait between each check to see if the vr flinger switch
-// completed.
-constexpr auto kVrFlingerSwitchPollInterval = std::chrono::milliseconds(50);
-
-// A Binder connection to surface flinger.
-class SurfaceFlingerConnection {
- public:
- static std::unique_ptr<SurfaceFlingerConnection> Create() {
- sp<ISurfaceComposer> surface_flinger = interface_cast<ISurfaceComposer>(
- defaultServiceManager()->getService(String16("SurfaceFlinger")));
- if (surface_flinger == nullptr) {
- return nullptr;
- }
-
- return std::unique_ptr<SurfaceFlingerConnection>(
- new SurfaceFlingerConnection(surface_flinger));
- }
-
- // Returns true if the surface flinger process is still running. We use this
- // to detect if surface flinger has crashed.
- bool IsAlive() {
- IInterface::asBinder(surface_flinger_)->pingBinder();
- return IInterface::asBinder(surface_flinger_)->isBinderAlive();
- }
-
- // Return true if vr flinger is currently active, false otherwise. If there's
- // an error communicating with surface flinger, std::nullopt is returned.
- std::optional<bool> IsVrFlingerActive() {
- Parcel data, reply;
- status_t result =
- data.writeInterfaceToken(surface_flinger_->getInterfaceDescriptor());
- if (result != OK) {
- return std::nullopt;
- }
- result = IInterface::asBinder(surface_flinger_)
- ->transact(kIsVrFlingerActiveTransactionCode, data, &reply);
- if (result != OK) {
- return std::nullopt;
- }
- bool vr_flinger_active;
- result = reply.readBool(&vr_flinger_active);
- if (result != OK) {
- return std::nullopt;
- }
- return vr_flinger_active;
- }
-
- enum class VrFlingerSwitchResult : int8_t {
- kSuccess,
- kTimedOut,
- kCommunicationError,
- kSurfaceFlingerDied
- };
-
- // Wait for vr flinger to become active or inactive.
- VrFlingerSwitchResult WaitForVrFlinger(bool wait_active) {
- return WaitForVrFlingerTimed(wait_active, kVrFlingerSwitchPollInterval,
- kVrFlingerSwitchMaxTime);
- }
-
- // Wait for vr flinger to become active or inactive, specifying custom timeouts.
- VrFlingerSwitchResult WaitForVrFlingerTimed(bool wait_active,
- std::chrono::milliseconds pollInterval, std::chrono::seconds timeout) {
- auto start_time = std::chrono::steady_clock::now();
- while (1) {
- std::this_thread::sleep_for(pollInterval);
- if (!IsAlive()) {
- return VrFlingerSwitchResult::kSurfaceFlingerDied;
- }
- std::optional<bool> vr_flinger_active = IsVrFlingerActive();
- if (!vr_flinger_active.has_value()) {
- return VrFlingerSwitchResult::kCommunicationError;
- }
- if (vr_flinger_active.value() == wait_active) {
- return VrFlingerSwitchResult::kSuccess;
- } else if (std::chrono::steady_clock::now() - start_time > timeout) {
- return VrFlingerSwitchResult::kTimedOut;
- }
- }
- }
-
- private:
- SurfaceFlingerConnection(sp<ISurfaceComposer> surface_flinger)
- : surface_flinger_(surface_flinger) {}
-
- sp<ISurfaceComposer> surface_flinger_ = nullptr;
-};
-
-// This test activates vr flinger by creating a vr flinger surface, then
-// deactivates vr flinger by destroying the surface. We verify that vr flinger
-// is activated and deactivated as expected, and that surface flinger doesn't
-// crash.
-//
-// If the device doesn't support vr flinger (as repoted by ConfigStore), the
-// test does nothing.
-//
-// If the device is a standalone vr device, the test also does nothing, since
-// this test verifies the behavior of display handoff from surface flinger to vr
-// flinger and back, and standalone devices never hand control of the display
-// back to surface flinger.
-TEST(VrFlingerTest, ActivateDeactivate) {
- android::ProcessState::self()->startThreadPool();
-
- // Exit immediately if the device doesn't support vr flinger. This ConfigStore
- // check is the same mechanism used by surface flinger to decide if it should
- // initialize vr flinger.
- bool vr_flinger_enabled = android::sysprop::use_vr_flinger(false);
- if (!vr_flinger_enabled) {
- return;
- }
-
- auto surface_flinger_connection = SurfaceFlingerConnection::Create();
- ASSERT_NE(surface_flinger_connection, nullptr);
-
- // Verify we start off with vr flinger disabled.
- ASSERT_TRUE(surface_flinger_connection->IsAlive());
- auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive();
- ASSERT_TRUE(vr_flinger_active.has_value());
- ASSERT_FALSE(vr_flinger_active.value());
-
- // Create a vr flinger surface, and verify vr flinger becomes active.
- // Introduce a scope so that, at the end of the scope, the vr flinger surface
- // is destroyed, and vr flinger deactivates.
- {
- auto display_client = DisplayClient::Create();
- ASSERT_NE(display_client, nullptr);
- auto metrics = display_client->GetDisplayMetrics();
- ASSERT_TRUE(metrics.ok());
-
- auto surface = Surface::CreateSurface({
- {SurfaceAttribute::Direct, SurfaceAttributeValue(true)},
- {SurfaceAttribute::Visible, SurfaceAttributeValue(true)},
- });
- ASSERT_TRUE(surface.ok());
- ASSERT_TRUE(surface.get() != nullptr);
-
- auto queue = surface.get()->CreateQueue(
- metrics.get().display_width, metrics.get().display_height,
- /*layer_count=*/1, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
- AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
- AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
- /*capacity=*/1,
- /*metadata_size=*/0);
- ASSERT_TRUE(queue.ok());
- ASSERT_TRUE(queue.get() != nullptr);
-
- size_t slot;
- pdx::LocalHandle release_fence;
- auto buffer = queue.get()->Dequeue(/*timeout=*/0, &slot, &release_fence);
- ASSERT_TRUE(buffer.ok());
- ASSERT_TRUE(buffer.get() != nullptr);
-
- ASSERT_EQ(buffer.get()->width(), metrics.get().display_width);
- ASSERT_EQ(buffer.get()->height(), metrics.get().display_height);
-
- void* raw_buf = nullptr;
- ASSERT_GE(buffer.get()->buffer()->Lock(
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, /*x=*/0, /*y=*/0,
- buffer.get()->width(), buffer.get()->height(), &raw_buf),
- 0);
- ASSERT_NE(raw_buf, nullptr);
- uint32_t* pixels = static_cast<uint32_t*>(raw_buf);
-
- for (int i = 0; i < buffer.get()->stride() * buffer.get()->height(); ++i) {
- pixels[i] = 0x0000ff00;
- }
-
- ASSERT_GE(buffer.get()->buffer()->Unlock(), 0);
-
- ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle()), 0);
-
- ASSERT_EQ(
- surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/true),
- SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
- }
-
- // Now that the vr flinger surface is destroyed, vr flinger should deactivate.
- ASSERT_EQ(
- surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/false),
- SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.filter b/libs/vr/libvrflinger/tests/vrflinger_test.filter
deleted file mode 100644
index 030bb7b..0000000
--- a/libs/vr/libvrflinger/tests/vrflinger_test.filter
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "presubmit": {
- "filter": "BootVrFlingerTest.*"
- }
-}
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
deleted file mode 100644
index a8a8476..0000000
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-#include <dvr/vr_flinger.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <memory>
-
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/dvr/display_client.h>
-#include <processgroup/sched_policy.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
-
-#include <functional>
-
-#include "DisplayHardware/ComposerHal.h"
-#include "display_manager_service.h"
-#include "display_service.h"
-
-namespace android {
-namespace dvr {
-
-std::unique_ptr<VrFlinger> VrFlinger::Create(
- Hwc2::Composer* hidl, hwc2_display_t primary_display_id,
- RequestDisplayCallback request_display_callback) {
- std::unique_ptr<VrFlinger> vr_flinger(new VrFlinger);
- if (vr_flinger->Init(hidl, primary_display_id, request_display_callback))
- return vr_flinger;
- else
- return nullptr;
-}
-
-VrFlinger::VrFlinger() {}
-
-VrFlinger::~VrFlinger() {
- if (persistent_vr_state_callback_.get()) {
- sp<IVrManager> vr_manager = interface_cast<IVrManager>(
- defaultServiceManager()->checkService(String16("vrmanager")));
- if (vr_manager.get()) {
- vr_manager->unregisterPersistentVrStateListener(
- persistent_vr_state_callback_);
- }
- }
-
- if (dispatcher_)
- dispatcher_->SetCanceled(true);
- if (dispatcher_thread_.joinable())
- dispatcher_thread_.join();
-}
-
-bool VrFlinger::Init(Hwc2::Composer* hidl,
- hwc2_display_t primary_display_id,
- RequestDisplayCallback request_display_callback) {
- if (!hidl || !request_display_callback)
- return false;
-
- std::shared_ptr<android::pdx::Service> service;
-
- ALOGI("Starting up VrFlinger...");
-
- // We need to be able to create endpoints with full perms.
- umask(0000);
-
- android::ProcessState::self()->startThreadPool();
-
- request_display_callback_ = request_display_callback;
-
- dispatcher_ = android::pdx::ServiceDispatcher::Create();
- CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher.");
-
- display_service_ = android::dvr::DisplayService::Create(
- hidl, primary_display_id, request_display_callback);
- CHECK_ERROR(!display_service_, error, "Failed to create display service.");
- dispatcher_->AddService(display_service_);
-
- service = android::dvr::DisplayManagerService::Create(display_service_);
- CHECK_ERROR(!service, error, "Failed to create display manager service.");
- dispatcher_->AddService(service);
-
- dispatcher_thread_ = std::thread([this]() {
- prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
- ALOGI("Entering message loop.");
-
- setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
- set_sched_policy(0, SP_FOREGROUND);
-
- int ret = dispatcher_->EnterDispatchLoop();
- if (ret < 0) {
- ALOGE("Dispatch loop exited because: %s\n", strerror(-ret));
- }
- });
-
- return true;
-
-error:
- return false;
-}
-
-void VrFlinger::OnBootFinished() {
- display_service_->OnBootFinished();
- sp<IVrManager> vr_manager = interface_cast<IVrManager>(
- defaultServiceManager()->checkService(String16("vrmanager")));
- if (vr_manager.get()) {
- persistent_vr_state_callback_ =
- new PersistentVrStateCallback(request_display_callback_);
- vr_manager->registerPersistentVrStateListener(
- persistent_vr_state_callback_);
- } else {
- ALOGE("Unable to register vr flinger for persistent vr mode changes");
- }
-}
-
-void VrFlinger::GrantDisplayOwnership() {
- display_service_->GrantDisplayOwnership();
-}
-
-void VrFlinger::SeizeDisplayOwnership() {
- display_service_->SeizeDisplayOwnership();
-}
-
-std::string VrFlinger::Dump() {
- // TODO(karthikrs): Add more state information here.
- return display_service_->DumpState(0/*unused*/);
-}
-
-void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
- bool enabled) {
- ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
- // TODO(eieio): Determine the correct signal to request display control.
- // Persistent VR mode is not enough.
- // request_display_callback_(enabled);
-}
-} // namespace dvr
-} // namespace android
diff --git a/services/inputflinger/dispatcher/EventLogTags.logtags b/services/inputflinger/dispatcher/EventLogTags.logtags
index 2836467..2c5fe21 100644
--- a/services/inputflinger/dispatcher/EventLogTags.logtags
+++ b/services/inputflinger/dispatcher/EventLogTags.logtags
@@ -37,6 +37,7 @@
62000 input_interaction (windows|4)
62001 input_focus (window|3),(reason|3)
+62003 input_cancel (window|3),(reason|3)
# NOTE - the range 1000000-2000000 is reserved for partners and others who
# want to define their own log tags without conflicting with the core platform.
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ea5799a..176cf89 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -153,6 +153,7 @@
// Event log tags. See EventLogTags.logtags for reference
constexpr int LOGTAG_INPUT_INTERACTION = 62000;
constexpr int LOGTAG_INPUT_FOCUS = 62001;
+constexpr int LOGTAG_INPUT_CANCEL = 62003;
inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
@@ -2077,6 +2078,8 @@
// Handle the case where we did not find a window.
if (newTouchedWindowHandle == nullptr) {
+ ALOGD("No new touched window at (%" PRId32 ", %" PRId32 ") in display %" PRId32, x, y,
+ displayId);
// Try to assign the pointer to the first foreground window we find, if there is one.
newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
}
@@ -2870,6 +2873,11 @@
if (!splitMotionEntry) {
return; // split event was dropped
}
+ if (splitMotionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
+ std::string reason = std::string("reason=pointer cancel on split window");
+ android_log_event_list(LOGTAG_INPUT_CANCEL)
+ << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS;
+ }
if (DEBUG_FOCUS) {
ALOGD("channel '%s' ~ Split motion event.",
connection->getInputChannelName().c_str());
@@ -3575,6 +3583,10 @@
options.mode);
}
+ std::string reason = std::string("reason=").append(options.reason);
+ android_log_event_list(LOGTAG_INPUT_CANCEL)
+ << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS;
+
InputTarget target;
sp<WindowInfoHandle> windowHandle =
getWindowHandleLocked(connection->inputChannel->getConnectionToken());
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 1879cec..ba0ce95 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2841,6 +2841,17 @@
ASSERT_EQ(ui::Transform(), event->getTransform());
}
+TEST_F(InputDispatcherTest, GestureMonitor_NoWindow) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
TEST_F(InputDispatcherTest, TestMoveEvent) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 75b2ba9..56b8374 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -39,15 +39,19 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.0",
"android.hardware.power@1.3",
- "android.hardware.power-V1-cpp",
+ "android.hardware.power-V2-cpp",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libEGL",
"libfmq",
@@ -69,18 +73,21 @@
"server_configurable_flags",
],
static_libs: [
+ "libaidlcommonsupport",
"libcompositionengine",
"libframetimeline",
"libperfetto_client_experimental",
"librenderengine",
"libserviceutils",
"libtrace_proto",
+ "libaidlcommonsupport",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
"android.hardware.graphics.composer@2.4-command-buffer",
+ "android.hardware.graphics.composer3-command-buffer",
],
export_static_lib_headers: [
"libcompositionengine",
@@ -95,6 +102,7 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.3",
"libhidlbase",
"libtimestats",
@@ -144,6 +152,8 @@
"EffectLayer.cpp",
"ContainerLayer.cpp",
"DisplayDevice.cpp",
+ "DisplayHardware/AidlComposerHal.cpp",
+ "DisplayHardware/HidlComposerHal.cpp",
"DisplayHardware/ComposerHal.cpp",
"DisplayHardware/DisplayIdentification.cpp",
"DisplayHardware/FramebufferSurface.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 969fd67..861d496 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -227,7 +227,7 @@
* of a camera where the buffer remains in native orientation,
* we want the pixels to always be upright.
*/
- auto p = mDrawingParent;
+ sp<Layer> p = mDrawingParent.promote();
if (p != nullptr) {
const auto parentTransform = p->getTransform();
tr = tr * inverseOrientation(parentTransform.getOrientation());
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 4e5d2d0..8aecec1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -118,7 +118,7 @@
bool BufferQueueLayer::fenceHasSignaled() const {
Mutex::Autolock lock(mQueueItemLock);
- if (SurfaceFlinger::enableLatchUnsignaled) {
+ if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
return true;
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 3e09a40..b6bea97 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -637,7 +637,7 @@
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool BufferStateLayer::fenceHasSignaled() const {
- if (SurfaceFlinger::enableLatchUnsignaled) {
+ if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
return true;
}
@@ -944,7 +944,7 @@
* how to go from screen space back to window space.
*/
ui::Transform BufferStateLayer::getInputTransform() const {
- auto parent = mDrawingParent;
+ sp<Layer> parent = mDrawingParent.promote();
if (parent == nullptr) {
return ui::Transform();
}
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index d738ccd..83b4a25 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -20,6 +20,7 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.0",
"android.hardware.power@1.3",
"libbase",
@@ -38,12 +39,14 @@
"libmath",
"librenderengine",
"libtrace_proto",
+ "libaidlcommonsupport",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
"android.hardware.graphics.composer@2.4-command-buffer",
+ "android.hardware.graphics.composer3-command-buffer",
"libsurfaceflinger_headers",
],
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index fc8cb50..db4151b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -29,11 +29,21 @@
PowerAdvisor();
~PowerAdvisor() override;
- MOCK_METHOD0(init, void());
- MOCK_METHOD0(onBootFinished, void());
- MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
- MOCK_METHOD0(isUsingExpensiveRendering, bool());
- MOCK_METHOD0(notifyDisplayUpdateImminent, void());
+ MOCK_METHOD(void, init, (), (override));
+ MOCK_METHOD(void, onBootFinished, (), (override));
+ MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected),
+ (override));
+ MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override));
+ MOCK_METHOD(void, notifyDisplayUpdateImminent, (), (override));
+ MOCK_METHOD(bool, usePowerHintSession, (), (override));
+ MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
+ MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
+ MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
+ MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
+ (override));
+ MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
+ (override));
+ MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
};
} // namespace mock
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
new file mode 100644
index 0000000..ba57be5
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -0,0 +1,1371 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "HwcComposer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "AidlComposerHal.h"
+
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_manager.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <aidl/android/hardware/graphics/composer3/BnComposerCallback.h>
+
+#include <algorithm>
+#include <cinttypes>
+
+namespace android {
+
+using hardware::hidl_handle;
+using hardware::hidl_vec;
+using hardware::Return;
+
+using aidl::android::hardware::graphics::composer3::BnComposerCallback;
+using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::PowerMode;
+using aidl::android::hardware::graphics::composer3::VirtualDisplay;
+
+using AidlColorMode = aidl::android::hardware::graphics::composer3::ColorMode;
+using AidlContentType = aidl::android::hardware::graphics::composer3::ContentType;
+using AidlDisplayIdentification =
+ aidl::android::hardware::graphics::composer3::DisplayIdentification;
+using AidlDisplayContentSample = aidl::android::hardware::graphics::composer3::DisplayContentSample;
+using AidlDisplayAttribute = aidl::android::hardware::graphics::composer3::DisplayAttribute;
+using AidlDisplayCapability = aidl::android::hardware::graphics::composer3::DisplayCapability;
+using AidlExecuteCommandsStatus =
+ aidl::android::hardware::graphics::composer3::ExecuteCommandsStatus;
+using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities;
+using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata;
+using AidlPerFrameMetadataKey = aidl::android::hardware::graphics::composer3::PerFrameMetadataKey;
+using AidlPerFrameMetadataBlob = aidl::android::hardware::graphics::composer3::PerFrameMetadataBlob;
+using AidlRenderIntent = aidl::android::hardware::graphics::composer3::RenderIntent;
+using AidlVsyncPeriodChangeConstraints =
+ aidl::android::hardware::graphics::composer3::VsyncPeriodChangeConstraints;
+using AidlVsyncPeriodChangeTimeline =
+ aidl::android::hardware::graphics::composer3::VsyncPeriodChangeTimeline;
+using AidlLayerGenericMetadataKey =
+ aidl::android::hardware::graphics::composer3::LayerGenericMetadataKey;
+using AidlDisplayContentSamplingAttributes =
+ aidl::android::hardware::graphics::composer3::DisplayContentSamplingAttributes;
+using AidlFormatColorComponent = aidl::android::hardware::graphics::composer3::FormatColorComponent;
+using AidlDisplayConnectionType =
+ aidl::android::hardware::graphics::composer3::DisplayConnectionType;
+using AidlIComposerClient = aidl::android::hardware::graphics::composer3::IComposerClient;
+
+using AidlColorTransform = aidl::android::hardware::graphics::common::ColorTransform;
+using AidlDataspace = aidl::android::hardware::graphics::common::Dataspace;
+using AidlFRect = aidl::android::hardware::graphics::common::FRect;
+using AidlRect = aidl::android::hardware::graphics::common::Rect;
+using AidlTransform = aidl::android::hardware::graphics::common::Transform;
+
+namespace Hwc2 {
+
+namespace {
+
+template <typename To, typename From>
+To translate(From x) {
+ return static_cast<To>(x);
+}
+
+template <typename To, typename From>
+std::vector<To> translate(const std::vector<From>& in) {
+ std::vector<To> out;
+ out.reserve(in.size());
+ std::transform(in.begin(), in.end(), std::back_inserter(out),
+ [](From x) { return translate<To>(x); });
+ return out;
+}
+
+template <>
+AidlRect translate(IComposerClient::Rect x) {
+ return AidlRect{
+ .left = x.left,
+ .top = x.top,
+ .right = x.right,
+ .bottom = x.bottom,
+ };
+}
+
+template <>
+AidlFRect translate(IComposerClient::FRect x) {
+ return AidlFRect{
+ .left = x.left,
+ .top = x.top,
+ .right = x.right,
+ .bottom = x.bottom,
+ };
+}
+
+template <>
+Color translate(IComposerClient::Color x) {
+ return Color{
+ .r = static_cast<int8_t>(x.r),
+ .g = static_cast<int8_t>(x.g),
+ .b = static_cast<int8_t>(x.b),
+ .a = static_cast<int8_t>(x.a),
+ };
+}
+
+template <>
+AidlPerFrameMetadataBlob translate(IComposerClient::PerFrameMetadataBlob x) {
+ AidlPerFrameMetadataBlob blob;
+ blob.key = translate<AidlPerFrameMetadataKey>(x.key),
+ std::copy(blob.blob.begin(), blob.blob.end(), x.blob.begin());
+ return blob;
+}
+
+template <>
+AidlPerFrameMetadata translate(IComposerClient::PerFrameMetadata x) {
+ return AidlPerFrameMetadata{
+ .key = translate<AidlPerFrameMetadataKey>(x.key),
+ .value = x.value,
+ };
+}
+
+template <>
+DisplayedFrameStats translate(AidlDisplayContentSample x) {
+ return DisplayedFrameStats{
+ .numFrames = static_cast<uint64_t>(x.frameCount),
+ .component_0_sample = translate<uint64_t>(x.sampleComponent0),
+ .component_1_sample = translate<uint64_t>(x.sampleComponent1),
+ .component_2_sample = translate<uint64_t>(x.sampleComponent2),
+ .component_3_sample = translate<uint64_t>(x.sampleComponent3),
+ };
+}
+
+template <>
+AidlVsyncPeriodChangeConstraints translate(IComposerClient::VsyncPeriodChangeConstraints x) {
+ return AidlVsyncPeriodChangeConstraints{
+ .desiredTimeNanos = x.desiredTimeNanos,
+ .seamlessRequired = x.seamlessRequired,
+ };
+}
+
+template <>
+VsyncPeriodChangeTimeline translate(AidlVsyncPeriodChangeTimeline x) {
+ return VsyncPeriodChangeTimeline{
+ .newVsyncAppliedTimeNanos = x.newVsyncAppliedTimeNanos,
+ .refreshRequired = x.refreshRequired,
+ .refreshTimeNanos = x.refreshTimeNanos,
+ };
+}
+
+template <>
+IComposerClient::LayerGenericMetadataKey translate(AidlLayerGenericMetadataKey x) {
+ return IComposerClient::LayerGenericMetadataKey{
+ .name = x.name,
+ .mandatory = x.mandatory,
+ };
+}
+
+mat4 makeMat4(std::vector<float> in) {
+ return mat4(static_cast<const float*>(in.data()));
+}
+
+} // namespace
+
+class AidlIComposerCallbackWrapper : public BnComposerCallback {
+public:
+ AidlIComposerCallbackWrapper(sp<V2_4::IComposerCallback> callback)
+ : mCallback(std::move(callback)) {}
+
+ ::ndk::ScopedAStatus onHotplug(int64_t in_display, bool in_connected) override {
+ const auto connection = in_connected ? V2_4::IComposerCallback::Connection::CONNECTED
+ : V2_4::IComposerCallback::Connection::DISCONNECTED;
+ mCallback->onHotplug(translate<Display>(in_display), connection);
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ ::ndk::ScopedAStatus onRefresh(int64_t in_display) override {
+ mCallback->onRefresh(translate<Display>(in_display));
+ return ::ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onSeamlessPossible(int64_t in_display) override {
+ mCallback->onSeamlessPossible(translate<Display>(in_display));
+ return ::ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onVsync(int64_t in_display, int64_t in_timestamp,
+ int32_t in_vsyncPeriodNanos) override {
+ mCallback->onVsync_2_4(translate<Display>(in_display), in_timestamp,
+ static_cast<uint32_t>(in_vsyncPeriodNanos));
+ return ::ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onVsyncPeriodTimingChanged(
+ int64_t in_display, const AidlVsyncPeriodChangeTimeline& in_updatedTimeline) override {
+ mCallback->onVsyncPeriodTimingChanged(translate<Display>(in_display),
+ translate<V2_4::VsyncPeriodChangeTimeline>(
+ in_updatedTimeline));
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+private:
+ sp<V2_4::IComposerCallback> mCallback;
+};
+
+std::string AidlComposer::instance(const std::string& serviceName) {
+ return std::string(AidlIComposer::descriptor) + "/" + serviceName;
+}
+
+bool AidlComposer::isDeclared(const std::string& serviceName) {
+ return AServiceManager_isDeclared(instance(serviceName).c_str());
+}
+
+AidlComposer::AidlComposer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
+ // This only waits if the service is actually declared
+ mAidlComposer = AidlIComposer::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(instance(serviceName).c_str())));
+ if (!mAidlComposer) {
+ LOG_ALWAYS_FATAL("Failed to get AIDL composer service");
+ return;
+ }
+
+ if (!mAidlComposer->createClient(&mAidlComposerClient).isOk()) {
+ LOG_ALWAYS_FATAL("Can't create AidlComposerClient, fallback to HIDL");
+ return;
+ }
+
+ ALOGI("Loaded AIDL composer3 HAL service");
+}
+
+AidlComposer::~AidlComposer() = default;
+
+std::vector<IComposer::Capability> AidlComposer::getCapabilities() {
+ std::vector<Capability> capabilities;
+ const auto status = mAidlComposer->getCapabilities(&capabilities);
+ if (!status.isOk()) {
+ ALOGE("getCapabilities failed %s", status.getDescription().c_str());
+ return {};
+ }
+ return translate<IComposer::Capability>(capabilities);
+}
+
+std::string AidlComposer::dumpDebugInfo() {
+ std::string info;
+ const auto status = mAidlComposer->dumpDebugInfo(&info);
+ if (!status.isOk()) {
+ ALOGE("dumpDebugInfo failed %s", status.getDescription().c_str());
+ return {};
+ }
+ return info;
+}
+
+void AidlComposer::registerCallback(const sp<IComposerCallback>& callback) {
+ if (mAidlComposerCallback) {
+ ALOGE("Callback already registered");
+ }
+ mAidlComposerCallback = ndk::SharedRefBase::make<AidlIComposerCallbackWrapper>(callback);
+ AIBinder_setMinSchedulerPolicy(mAidlComposerCallback->asBinder().get(), SCHED_FIFO, 2);
+
+ const auto status = mAidlComposerClient->registerCallback(mAidlComposerCallback);
+ if (!status.isOk()) {
+ ALOGE("registerCallback failed %s", status.getDescription().c_str());
+ }
+}
+
+void AidlComposer::resetCommands() {
+ mWriter.reset();
+}
+
+Error AidlComposer::executeCommands() {
+ return execute();
+}
+
+uint32_t AidlComposer::getMaxVirtualDisplayCount() {
+ int32_t count = 0;
+ const auto status = mAidlComposerClient->getMaxVirtualDisplayCount(&count);
+ if (!status.isOk()) {
+ ALOGE("getMaxVirtualDisplayCount failed %s", status.getDescription().c_str());
+ return 0;
+ }
+ return static_cast<uint32_t>(count);
+}
+
+Error AidlComposer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+ Display* outDisplay) {
+ using AidlPixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
+ const int32_t bufferSlotCount = 1;
+ VirtualDisplay virtualDisplay;
+ const auto status =
+ mAidlComposerClient->createVirtualDisplay(static_cast<int32_t>(width),
+ static_cast<int32_t>(height),
+ static_cast<AidlPixelFormat>(*format),
+ bufferSlotCount, &virtualDisplay);
+
+ if (!status.isOk()) {
+ ALOGE("createVirtualDisplay failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+
+ *outDisplay = translate<Display>(virtualDisplay.display);
+ *format = static_cast<PixelFormat>(virtualDisplay.format);
+ return Error::NONE;
+}
+
+Error AidlComposer::destroyVirtualDisplay(Display display) {
+ const auto status = mAidlComposerClient->destroyVirtualDisplay(translate<int64_t>(display));
+ if (!status.isOk()) {
+ ALOGE("destroyVirtualDisplay failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::acceptDisplayChanges(Display display) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.acceptDisplayChanges();
+ return Error::NONE;
+}
+
+Error AidlComposer::createLayer(Display display, Layer* outLayer) {
+ int64_t layer;
+ const auto status = mAidlComposerClient->createLayer(translate<int64_t>(display),
+ kMaxLayerBufferCount, &layer);
+ if (!status.isOk()) {
+ ALOGE("createLayer failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+
+ *outLayer = translate<Layer>(layer);
+ return Error::NONE;
+}
+
+Error AidlComposer::destroyLayer(Display display, Layer layer) {
+ const auto status = mAidlComposerClient->destroyLayer(translate<int64_t>(display),
+ translate<int64_t>(layer));
+ if (!status.isOk()) {
+ ALOGE("destroyLayer failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::getActiveConfig(Display display, Config* outConfig) {
+ int32_t config;
+ const auto status = mAidlComposerClient->getActiveConfig(translate<int64_t>(display), &config);
+ if (!status.isOk()) {
+ ALOGE("getActiveConfig failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *outConfig = translate<Config>(config);
+ return Error::NONE;
+}
+
+Error AidlComposer::getChangedCompositionTypes(
+ Display display, std::vector<Layer>* outLayers,
+ std::vector<IComposerClient::Composition>* outTypes) {
+ mReader.takeChangedCompositionTypes(display, outLayers, outTypes);
+ return Error::NONE;
+}
+
+Error AidlComposer::getColorModes(Display display, std::vector<ColorMode>* outModes) {
+ std::vector<AidlColorMode> modes;
+ const auto status = mAidlComposerClient->getColorModes(translate<int64_t>(display), &modes);
+ if (!status.isOk()) {
+ ALOGE("getColorModes failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *outModes = translate<ColorMode>(modes);
+ return Error::NONE;
+}
+
+Error AidlComposer::getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute, int32_t* outValue) {
+ const auto status =
+ mAidlComposerClient->getDisplayAttribute(translate<int64_t>(display),
+ translate<int32_t>(config),
+ static_cast<AidlDisplayAttribute>(attribute),
+ outValue);
+ if (!status.isOk()) {
+ ALOGE("getDisplayAttribute failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::getDisplayConfigs(Display display, std::vector<Config>* outConfigs) {
+ std::vector<int32_t> configs;
+ const auto status =
+ mAidlComposerClient->getDisplayConfigs(translate<int64_t>(display), &configs);
+ if (!status.isOk()) {
+ ALOGE("getDisplayConfigs failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *outConfigs = translate<Config>(configs);
+ return Error::NONE;
+}
+
+Error AidlComposer::getDisplayName(Display display, std::string* outName) {
+ const auto status = mAidlComposerClient->getDisplayName(translate<int64_t>(display), outName);
+ if (!status.isOk()) {
+ ALOGE("getDisplayName failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outLayers,
+ std::vector<uint32_t>* outLayerRequestMasks) {
+ mReader.takeDisplayRequests(display, outDisplayRequestMask, outLayers, outLayerRequestMasks);
+ return Error::NONE;
+}
+
+Error AidlComposer::getDozeSupport(Display display, bool* outSupport) {
+ const auto status =
+ mAidlComposerClient->getDozeSupport(translate<int64_t>(display), outSupport);
+ if (!status.isOk()) {
+ ALOGE("getDozeSupport failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
+ float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance) {
+ AidlHdrCapabilities capabilities;
+ const auto status =
+ mAidlComposerClient->getHdrCapabilities(translate<int64_t>(display), &capabilities);
+ if (!status.isOk()) {
+ ALOGE("getHdrCapabilities failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+
+ *outTypes = translate<Hdr>(capabilities.types);
+ *outMaxLuminance = capabilities.maxLuminance;
+ *outMaxAverageLuminance = capabilities.maxAverageLuminance;
+ *outMinLuminance = capabilities.minLuminance;
+ return Error::NONE;
+}
+
+Error AidlComposer::getReleaseFences(Display display, std::vector<Layer>* outLayers,
+ std::vector<int>* outReleaseFences) {
+ mReader.takeReleaseFences(display, outLayers, outReleaseFences);
+ return Error::NONE;
+}
+
+Error AidlComposer::presentDisplay(Display display, int* outPresentFence) {
+ ATRACE_NAME("HwcPresentDisplay");
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.presentDisplay();
+
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ mReader.takePresentFence(display, outPresentFence);
+
+ return Error::NONE;
+}
+
+Error AidlComposer::setActiveConfig(Display display, Config config) {
+ const auto status = mAidlComposerClient->setActiveConfig(translate<int64_t>(display),
+ translate<int32_t>(config));
+ if (!status.isOk()) {
+ ALOGE("setActiveConfig failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
+ int acquireFence, Dataspace dataspace,
+ const std::vector<IComposerClient::Rect>& damage) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+
+ const native_handle_t* handle = nullptr;
+ if (target.get()) {
+ handle = target->getNativeBuffer()->handle;
+ }
+
+ mWriter.setClientTarget(slot, handle, acquireFence,
+ translate<aidl::android::hardware::graphics::common::Dataspace>(
+ dataspace),
+ translate<AidlRect>(damage));
+ return Error::NONE;
+}
+
+Error AidlComposer::setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) {
+ const auto status =
+ mAidlComposerClient->setColorMode(translate<int64_t>(display),
+ translate<AidlColorMode>(mode),
+ translate<AidlRenderIntent>(renderIntent));
+ if (!status.isOk()) {
+ ALOGE("setColorMode failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::setColorTransform(Display display, const float* matrix, ColorTransform hint) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.setColorTransform(matrix, translate<AidlColorTransform>(hint));
+ return Error::NONE;
+}
+
+Error AidlComposer::setOutputBuffer(Display display, const native_handle_t* buffer,
+ int releaseFence) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.setOutputBuffer(0, buffer, dup(releaseFence));
+ return Error::NONE;
+}
+
+Error AidlComposer::setPowerMode(Display display, IComposerClient::PowerMode mode) {
+ const auto status = mAidlComposerClient->setPowerMode(translate<int64_t>(display),
+ translate<PowerMode>(mode));
+ if (!status.isOk()) {
+ ALOGE("setPowerMode failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
+ const bool enableVsync = enabled == IComposerClient::Vsync::ENABLE;
+ const auto status =
+ mAidlComposerClient->setVsyncEnabled(translate<int64_t>(display), enableVsync);
+ if (!status.isOk()) {
+ ALOGE("setVsyncEnabled failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::setClientTargetSlotCount(Display display) {
+ const int32_t bufferSlotCount = BufferQueue::NUM_BUFFER_SLOTS;
+ const auto status = mAidlComposerClient->setClientTargetSlotCount(translate<int64_t>(display),
+ bufferSlotCount);
+ if (!status.isOk()) {
+ ALOGE("setClientTargetSlotCount failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::validateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests) {
+ ATRACE_NAME("HwcValidateDisplay");
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.validateDisplay();
+
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ mReader.hasChanges(display, outNumTypes, outNumRequests);
+
+ return Error::NONE;
+}
+
+Error AidlComposer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests, int* outPresentFence,
+ uint32_t* state) {
+ ATRACE_NAME("HwcPresentOrValidateDisplay");
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.presentOrvalidateDisplay();
+
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ mReader.takePresentOrValidateStage(display, state);
+
+ if (*state == 1) { // Present succeeded
+ mReader.takePresentFence(display, outPresentFence);
+ }
+
+ if (*state == 0) { // Validate succeeded.
+ mReader.hasChanges(display, outNumTypes, outNumRequests);
+ }
+
+ return Error::NONE;
+}
+
+Error AidlComposer::setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerCursorPosition(x, y);
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerBuffer(Display display, Layer layer, uint32_t slot,
+ const sp<GraphicBuffer>& buffer, int acquireFence) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+
+ const native_handle_t* handle = nullptr;
+ if (buffer.get()) {
+ handle = buffer->getNativeBuffer()->handle;
+ }
+
+ mWriter.setLayerBuffer(slot, handle, acquireFence);
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& damage) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerSurfaceDamage(translate<AidlRect>(damage));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerBlendMode(Display display, Layer layer,
+ IComposerClient::BlendMode mode) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerBlendMode(translate<BlendMode>(mode));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerColor(Display display, Layer layer,
+ const IComposerClient::Color& color) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerColor(translate<Color>(color));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerCompositionType(Display display, Layer layer,
+ IComposerClient::Composition type) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerCompositionType(translate<Composition>(type));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerDataspace(Display display, Layer layer, Dataspace dataspace) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerDataspace(translate<AidlDataspace>(dataspace));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerDisplayFrame(Display display, Layer layer,
+ const IComposerClient::Rect& frame) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerDisplayFrame(translate<AidlRect>(frame));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerPlaneAlpha(alpha);
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerSidebandStream(Display display, Layer layer,
+ const native_handle_t* stream) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerSidebandStream(stream);
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerSourceCrop(Display display, Layer layer,
+ const IComposerClient::FRect& crop) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerSourceCrop(translate<AidlFRect>(crop));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerTransform(Display display, Layer layer, Transform transform) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerTransform(translate<AidlTransform>(transform));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& visible) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerVisibleRegion(translate<AidlRect>(visible));
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerZOrder(Display display, Layer layer, uint32_t z) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerZOrder(z);
+ return Error::NONE;
+}
+
+Error AidlComposer::execute() {
+ // prepare input command queue
+ bool queueChanged = false;
+ int32_t commandLength = 0;
+ std::vector<aidl::android::hardware::common::NativeHandle> commandHandles;
+ if (!mWriter.writeQueue(&queueChanged, &commandLength, &commandHandles)) {
+ mWriter.reset();
+ return Error::NO_RESOURCES;
+ }
+
+ // set up new input command queue if necessary
+ if (queueChanged) {
+ const auto status = mAidlComposerClient->setInputCommandQueue(mWriter.getMQDescriptor());
+ if (!status.isOk()) {
+ ALOGE("setInputCommandQueue failed %s", status.getDescription().c_str());
+ mWriter.reset();
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ }
+
+ if (commandLength == 0) {
+ mWriter.reset();
+ return Error::NONE;
+ }
+
+ AidlExecuteCommandsStatus commandStatus;
+ auto status =
+ mAidlComposerClient->executeCommands(commandLength, commandHandles, &commandStatus);
+ // executeCommands can fail because of out-of-fd and we do not want to
+ // abort() in that case
+ if (!status.isOk()) {
+ ALOGE("executeCommands failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+
+ // set up new output command queue if necessary
+ if (commandStatus.queueChanged) {
+ ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ outputCommandQueue;
+ status = mAidlComposerClient->getOutputCommandQueue(&outputCommandQueue);
+ if (!status.isOk()) {
+ ALOGE("getOutputCommandQueue failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+
+ mReader.setMQDescriptor(outputCommandQueue);
+ }
+
+ Error error;
+ if (mReader.readQueue(commandStatus.length, std::move(commandStatus.handles))) {
+ error = static_cast<Error>(mReader.parse());
+ mReader.reset();
+ } else {
+ error = Error::NO_RESOURCES;
+ }
+
+ if (error == Error::NONE) {
+ std::vector<AidlCommandReader::CommandError> commandErrors = mReader.takeErrors();
+
+ for (const auto& cmdErr : commandErrors) {
+ auto command = mWriter.getCommand(cmdErr.location);
+ if (command == Command::VALIDATE_DISPLAY || command == Command::PRESENT_DISPLAY ||
+ command == Command::PRESENT_OR_VALIDATE_DISPLAY) {
+ error = cmdErr.error;
+ } else {
+ ALOGW("command 0x%x generated error %d", command, cmdErr.error);
+ }
+ }
+ }
+
+ mWriter.reset();
+
+ return error;
+}
+
+Error AidlComposer::setLayerPerFrameMetadata(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerPerFrameMetadata(translate<AidlPerFrameMetadata>(perFrameMetadatas));
+ return Error::NONE;
+}
+
+std::vector<IComposerClient::PerFrameMetadataKey> AidlComposer::getPerFrameMetadataKeys(
+ Display display) {
+ std::vector<AidlPerFrameMetadataKey> keys;
+ const auto status =
+ mAidlComposerClient->getPerFrameMetadataKeys(translate<int64_t>(display), &keys);
+ if (!status.isOk()) {
+ ALOGE("getPerFrameMetadataKeys failed %s", status.getDescription().c_str());
+ return {};
+ }
+ return translate<IComposerClient::PerFrameMetadataKey>(keys);
+}
+
+Error AidlComposer::getRenderIntents(Display display, ColorMode colorMode,
+ std::vector<RenderIntent>* outRenderIntents) {
+ std::vector<AidlRenderIntent> renderIntents;
+ const auto status = mAidlComposerClient->getRenderIntents(translate<int64_t>(display),
+ translate<AidlColorMode>(colorMode),
+ &renderIntents);
+ if (!status.isOk()) {
+ ALOGE("getRenderIntents failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *outRenderIntents = translate<RenderIntent>(renderIntents);
+ return Error::NONE;
+}
+
+Error AidlComposer::getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) {
+ std::vector<float> matrix;
+ const auto status =
+ mAidlComposerClient->getDataspaceSaturationMatrix(translate<AidlDataspace>(dataspace),
+ &matrix);
+ if (!status.isOk()) {
+ ALOGE("getDataspaceSaturationMatrix failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *outMatrix = makeMat4(matrix);
+ return Error::NONE;
+}
+
+Error AidlComposer::getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) {
+ AidlDisplayIdentification displayIdentification;
+ const auto status =
+ mAidlComposerClient->getDisplayIdentificationData(translate<int64_t>(display),
+ &displayIdentification);
+ if (!status.isOk()) {
+ ALOGE("getDisplayIdentificationData failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+
+ *outPort = static_cast<uint8_t>(displayIdentification.port);
+ *outData = displayIdentification.data;
+
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerColorTransform(Display display, Layer layer, const float* matrix) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerColorTransform(matrix);
+ return Error::NONE;
+}
+
+Error AidlComposer::getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace,
+ uint8_t* outComponentMask) {
+ if (!outFormat || !outDataspace || !outComponentMask) {
+ return Error::BAD_PARAMETER;
+ }
+
+ AidlDisplayContentSamplingAttributes attributes;
+ const auto status =
+ mAidlComposerClient->getDisplayedContentSamplingAttributes(translate<int64_t>(display),
+ &attributes);
+ if (!status.isOk()) {
+ ALOGE("getDisplayedContentSamplingAttributes failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+
+ *outFormat = translate<PixelFormat>(attributes.format);
+ *outDataspace = translate<Dataspace>(attributes.dataspace);
+ *outComponentMask = static_cast<uint8_t>(attributes.componentMask);
+ return Error::NONE;
+}
+
+Error AidlComposer::setDisplayContentSamplingEnabled(Display display, bool enabled,
+ uint8_t componentMask, uint64_t maxFrames) {
+ const auto status =
+ mAidlComposerClient
+ ->setDisplayedContentSamplingEnabled(translate<int64_t>(display), enabled,
+ static_cast<AidlFormatColorComponent>(
+ componentMask),
+ static_cast<int64_t>(maxFrames));
+ if (!status.isOk()) {
+ ALOGE("setDisplayedContentSamplingEnabled failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::getDisplayedContentSample(Display display, uint64_t maxFrames,
+ uint64_t timestamp, DisplayedFrameStats* outStats) {
+ if (!outStats) {
+ return Error::BAD_PARAMETER;
+ }
+
+ AidlDisplayContentSample sample;
+ const auto status =
+ mAidlComposerClient->getDisplayedContentSample(translate<int64_t>(display),
+ static_cast<int64_t>(maxFrames),
+ static_cast<int64_t>(timestamp),
+ &sample);
+ if (!status.isOk()) {
+ ALOGE("getDisplayedContentSample failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *outStats = translate<DisplayedFrameStats>(sample);
+ return Error::NONE;
+}
+
+Error AidlComposer::setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerPerFrameMetadataBlobs(translate<AidlPerFrameMetadataBlob>(metadata));
+ return Error::NONE;
+}
+
+Error AidlComposer::setDisplayBrightness(Display display, float brightness) {
+ const auto status =
+ mAidlComposerClient->setDisplayBrightness(translate<int64_t>(display), brightness);
+ if (!status.isOk()) {
+ ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::getDisplayCapabilities(Display display,
+ std::vector<DisplayCapability>* outCapabilities) {
+ std::vector<AidlDisplayCapability> capabilities;
+ const auto status =
+ mAidlComposerClient->getDisplayCapabilities(translate<int64_t>(display), &capabilities);
+ if (!status.isOk()) {
+ ALOGE("getDisplayCapabilities failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *outCapabilities = translate<DisplayCapability>(capabilities);
+ return Error::NONE;
+}
+
+V2_4::Error AidlComposer::getDisplayConnectionType(
+ Display display, IComposerClient::DisplayConnectionType* outType) {
+ AidlDisplayConnectionType type;
+ const auto status =
+ mAidlComposerClient->getDisplayConnectionType(translate<int64_t>(display), &type);
+ if (!status.isOk()) {
+ ALOGE("getDisplayConnectionType failed %s", status.getDescription().c_str());
+ return static_cast<V2_4::Error>(status.getServiceSpecificError());
+ }
+ *outType = translate<IComposerClient::DisplayConnectionType>(type);
+ return V2_4::Error::NONE;
+}
+
+V2_4::Error AidlComposer::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) {
+ int32_t vsyncPeriod;
+ const auto status =
+ mAidlComposerClient->getDisplayVsyncPeriod(translate<int64_t>(display), &vsyncPeriod);
+ if (!status.isOk()) {
+ ALOGE("getDisplayVsyncPeriod failed %s", status.getDescription().c_str());
+ return static_cast<V2_4::Error>(status.getServiceSpecificError());
+ }
+ *outVsyncPeriod = translate<VsyncPeriodNanos>(vsyncPeriod);
+ return V2_4::Error::NONE;
+}
+
+V2_4::Error AidlComposer::setActiveConfigWithConstraints(
+ Display display, Config config,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ VsyncPeriodChangeTimeline* outTimeline) {
+ AidlVsyncPeriodChangeTimeline timeline;
+ const auto status =
+ mAidlComposerClient
+ ->setActiveConfigWithConstraints(translate<int64_t>(display),
+ translate<int32_t>(config),
+ translate<AidlVsyncPeriodChangeConstraints>(
+ vsyncPeriodChangeConstraints),
+ &timeline);
+ if (!status.isOk()) {
+ ALOGE("setActiveConfigWithConstraints failed %s", status.getDescription().c_str());
+ return static_cast<V2_4::Error>(status.getServiceSpecificError());
+ }
+ *outTimeline = translate<VsyncPeriodChangeTimeline>(timeline);
+ return V2_4::Error::NONE;
+}
+
+V2_4::Error AidlComposer::setAutoLowLatencyMode(Display display, bool on) {
+ const auto status = mAidlComposerClient->setAutoLowLatencyMode(translate<int64_t>(display), on);
+ if (!status.isOk()) {
+ ALOGE("setAutoLowLatencyMode failed %s", status.getDescription().c_str());
+ return static_cast<V2_4::Error>(status.getServiceSpecificError());
+ }
+ return V2_4::Error::NONE;
+}
+
+V2_4::Error AidlComposer::getSupportedContentTypes(
+ Display displayId, std::vector<IComposerClient::ContentType>* outSupportedContentTypes) {
+ std::vector<AidlContentType> types;
+ const auto status =
+ mAidlComposerClient->getSupportedContentTypes(translate<int64_t>(displayId), &types);
+ if (!status.isOk()) {
+ ALOGE("getSupportedContentTypes failed %s", status.getDescription().c_str());
+ return static_cast<V2_4::Error>(status.getServiceSpecificError());
+ }
+ *outSupportedContentTypes = translate<IComposerClient::ContentType>(types);
+ return V2_4::Error::NONE;
+}
+
+V2_4::Error AidlComposer::setContentType(Display display,
+ IComposerClient::ContentType contentType) {
+ const auto status =
+ mAidlComposerClient->setContentType(translate<int64_t>(display),
+ translate<AidlContentType>(contentType));
+ if (!status.isOk()) {
+ ALOGE("setContentType failed %s", status.getDescription().c_str());
+ return static_cast<V2_4::Error>(status.getServiceSpecificError());
+ }
+ return V2_4::Error::NONE;
+}
+
+V2_4::Error AidlComposer::setLayerGenericMetadata(Display display, Layer layer,
+ const std::string& key, bool mandatory,
+ const std::vector<uint8_t>& value) {
+ mWriter.selectDisplay(translate<int64_t>(display));
+ mWriter.selectLayer(translate<int64_t>(layer));
+ mWriter.setLayerGenericMetadata(key, mandatory, value);
+ return V2_4::Error::NONE;
+}
+
+V2_4::Error AidlComposer::getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
+ std::vector<AidlLayerGenericMetadataKey> keys;
+ const auto status = mAidlComposerClient->getLayerGenericMetadataKeys(&keys);
+ if (!status.isOk()) {
+ ALOGE("getLayerGenericMetadataKeys failed %s", status.getDescription().c_str());
+ return static_cast<V2_4::Error>(status.getServiceSpecificError());
+ }
+ *outKeys = translate<IComposerClient::LayerGenericMetadataKey>(keys);
+ return V2_4::Error::NONE;
+}
+
+Error AidlComposer::getClientTargetProperty(
+ Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
+ mReader.takeClientTargetProperty(display, outClientTargetProperty);
+ return Error::NONE;
+}
+
+AidlCommandReader::~AidlCommandReader() {
+ resetData();
+}
+
+int AidlCommandReader::parse() {
+ resetData();
+
+ Command command;
+ uint16_t length = 0;
+
+ while (!isEmpty()) {
+ if (!beginCommand(&command, &length)) {
+ break;
+ }
+
+ bool parsed = false;
+ switch (command) {
+ case Command::SELECT_DISPLAY:
+ parsed = parseSelectDisplay(length);
+ break;
+ case Command::SET_ERROR:
+ parsed = parseSetError(length);
+ break;
+ case Command::SET_CHANGED_COMPOSITION_TYPES:
+ parsed = parseSetChangedCompositionTypes(length);
+ break;
+ case Command::SET_DISPLAY_REQUESTS:
+ parsed = parseSetDisplayRequests(length);
+ break;
+ case Command::SET_PRESENT_FENCE:
+ parsed = parseSetPresentFence(length);
+ break;
+ case Command::SET_RELEASE_FENCES:
+ parsed = parseSetReleaseFences(length);
+ break;
+ case Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
+ parsed = parseSetPresentOrValidateDisplayResult(length);
+ break;
+ case Command::SET_CLIENT_TARGET_PROPERTY:
+ parsed = parseSetClientTargetProperty(length);
+ break;
+ default:
+ parsed = false;
+ break;
+ }
+
+ endCommand();
+
+ if (!parsed) {
+ ALOGE("failed to parse command 0x%x length %" PRIu16, command, length);
+ break;
+ }
+ }
+
+ return isEmpty() ? 0 : AidlIComposerClient::EX_NO_RESOURCES;
+}
+
+bool AidlCommandReader::parseSelectDisplay(uint16_t length) {
+ if (length != CommandWriterBase::kSelectDisplayLength) {
+ return false;
+ }
+
+ mCurrentReturnData = &mReturnData[read64()];
+
+ return true;
+}
+
+bool AidlCommandReader::parseSetError(uint16_t length) {
+ if (length != CommandWriterBase::kSetErrorLength) {
+ return false;
+ }
+
+ auto location = read();
+ auto error = static_cast<Error>(readSigned());
+
+ mErrors.emplace_back(CommandError{location, error});
+
+ return true;
+}
+
+bool AidlCommandReader::parseSetChangedCompositionTypes(uint16_t length) {
+ // (layer id [64bit], composition type [32bit]) pairs
+ static constexpr int kCommandWords = 3;
+
+ if (length % kCommandWords != 0 || !mCurrentReturnData) {
+ return false;
+ }
+
+ uint32_t count = length / kCommandWords;
+ mCurrentReturnData->changedLayers.reserve(count);
+ mCurrentReturnData->compositionTypes.reserve(count);
+ while (count > 0) {
+ auto layer = read64();
+ auto type = static_cast<IComposerClient::Composition>(readSigned());
+
+ mCurrentReturnData->changedLayers.push_back(layer);
+ mCurrentReturnData->compositionTypes.push_back(type);
+
+ count--;
+ }
+
+ return true;
+}
+
+bool AidlCommandReader::parseSetDisplayRequests(uint16_t length) {
+ // display requests [32 bit] followed by
+ // (layer id [64bit], layer requests [32bit]) pairs
+ static constexpr int kDisplayRequestsWords = 1;
+ static constexpr int kCommandWords = 3;
+ if (length % kCommandWords != kDisplayRequestsWords || !mCurrentReturnData) {
+ return false;
+ }
+
+ mCurrentReturnData->displayRequests = read();
+
+ uint32_t count = (length - kDisplayRequestsWords) / kCommandWords;
+ mCurrentReturnData->requestedLayers.reserve(count);
+ mCurrentReturnData->requestMasks.reserve(count);
+ while (count > 0) {
+ auto layer = read64();
+ auto layerRequestMask = read();
+
+ mCurrentReturnData->requestedLayers.push_back(layer);
+ mCurrentReturnData->requestMasks.push_back(layerRequestMask);
+
+ count--;
+ }
+
+ return true;
+}
+
+bool AidlCommandReader::parseSetPresentFence(uint16_t length) {
+ if (length != CommandWriterBase::kSetPresentFenceLength || !mCurrentReturnData) {
+ return false;
+ }
+
+ if (mCurrentReturnData->presentFence >= 0) {
+ close(mCurrentReturnData->presentFence);
+ }
+ mCurrentReturnData->presentFence = readFence();
+
+ return true;
+}
+
+bool AidlCommandReader::parseSetReleaseFences(uint16_t length) {
+ // (layer id [64bit], release fence index [32bit]) pairs
+ static constexpr int kCommandWords = 3;
+
+ if (length % kCommandWords != 0 || !mCurrentReturnData) {
+ return false;
+ }
+
+ uint32_t count = length / kCommandWords;
+ mCurrentReturnData->releasedLayers.reserve(count);
+ mCurrentReturnData->releaseFences.reserve(count);
+ while (count > 0) {
+ auto layer = read64();
+ auto fence = readFence();
+
+ mCurrentReturnData->releasedLayers.push_back(layer);
+ mCurrentReturnData->releaseFences.push_back(fence);
+
+ count--;
+ }
+
+ return true;
+}
+
+bool AidlCommandReader::parseSetPresentOrValidateDisplayResult(uint16_t length) {
+ if (length != CommandWriterBase::kPresentOrValidateDisplayResultLength || !mCurrentReturnData) {
+ return false;
+ }
+ mCurrentReturnData->presentOrValidateState = read();
+ return true;
+}
+
+bool AidlCommandReader::parseSetClientTargetProperty(uint16_t length) {
+ if (length != CommandWriterBase::kSetClientTargetPropertyLength || !mCurrentReturnData) {
+ return false;
+ }
+ mCurrentReturnData->clientTargetProperty.pixelFormat = static_cast<PixelFormat>(readSigned());
+ mCurrentReturnData->clientTargetProperty.dataspace = static_cast<Dataspace>(readSigned());
+ return true;
+}
+
+void AidlCommandReader::resetData() {
+ mErrors.clear();
+
+ for (auto& data : mReturnData) {
+ if (data.second.presentFence >= 0) {
+ close(data.second.presentFence);
+ }
+ for (auto fence : data.second.releaseFences) {
+ if (fence >= 0) {
+ close(fence);
+ }
+ }
+ }
+
+ mReturnData.clear();
+ mCurrentReturnData = nullptr;
+}
+
+std::vector<AidlCommandReader::CommandError> AidlCommandReader::takeErrors() {
+ return std::move(mErrors);
+}
+
+bool AidlCommandReader::hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
+ uint32_t* outNumLayerRequestMasks) const {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *outNumChangedCompositionTypes = 0;
+ *outNumLayerRequestMasks = 0;
+ return false;
+ }
+
+ const ReturnData& data = found->second;
+
+ *outNumChangedCompositionTypes = static_cast<uint32_t>(data.compositionTypes.size());
+ *outNumLayerRequestMasks = static_cast<uint32_t>(data.requestMasks.size());
+
+ return !(data.compositionTypes.empty() && data.requestMasks.empty());
+}
+
+void AidlCommandReader::takeChangedCompositionTypes(
+ Display display, std::vector<Layer>* outLayers,
+ std::vector<IComposerClient::Composition>* outTypes) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ outLayers->clear();
+ outTypes->clear();
+ return;
+ }
+
+ ReturnData& data = found->second;
+
+ *outLayers = std::move(data.changedLayers);
+ *outTypes = std::move(data.compositionTypes);
+}
+
+void AidlCommandReader::takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outLayers,
+ std::vector<uint32_t>* outLayerRequestMasks) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *outDisplayRequestMask = 0;
+ outLayers->clear();
+ outLayerRequestMasks->clear();
+ return;
+ }
+
+ ReturnData& data = found->second;
+
+ *outDisplayRequestMask = data.displayRequests;
+ *outLayers = std::move(data.requestedLayers);
+ *outLayerRequestMasks = std::move(data.requestMasks);
+}
+
+void AidlCommandReader::takeReleaseFences(Display display, std::vector<Layer>* outLayers,
+ std::vector<int>* outReleaseFences) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ outLayers->clear();
+ outReleaseFences->clear();
+ return;
+ }
+
+ ReturnData& data = found->second;
+
+ *outLayers = std::move(data.releasedLayers);
+ *outReleaseFences = std::move(data.releaseFences);
+}
+
+void AidlCommandReader::takePresentFence(Display display, int* outPresentFence) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *outPresentFence = -1;
+ return;
+ }
+
+ ReturnData& data = found->second;
+
+ *outPresentFence = data.presentFence;
+ data.presentFence = -1;
+}
+
+void AidlCommandReader::takePresentOrValidateStage(Display display, uint32_t* state) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *state = static_cast<uint32_t>(-1);
+ return;
+ }
+ ReturnData& data = found->second;
+ *state = data.presentOrValidateState;
+}
+
+void AidlCommandReader::takeClientTargetProperty(
+ Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
+ auto found = mReturnData.find(display);
+
+ // If not found, return the default values.
+ if (found == mReturnData.end()) {
+ outClientTargetProperty->pixelFormat = PixelFormat::RGBA_8888;
+ outClientTargetProperty->dataspace = Dataspace::UNKNOWN;
+ return;
+ }
+
+ ReturnData& data = found->second;
+ *outClientTargetProperty = data.clientTargetProperty;
+}
+
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
new file mode 100644
index 0000000..a6d9500
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -0,0 +1,320 @@
+/*
+ * 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 "ComposerHal.h"
+
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+// 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 <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+
+#include <aidl/android/hardware/graphics/composer3/IComposer.h>
+#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <android/hardware/graphics/composer3/command-buffer.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+
+namespace android::Hwc2 {
+
+using AidlCommandWriterBase = aidl::android::hardware::graphics::composer3::CommandWriterBase;
+using AidlCommandReaderBase = aidl::android::hardware::graphics::composer3::CommandReaderBase;
+
+class AidlIComposerCallbackWrapper;
+
+class AidlCommandReader : public AidlCommandReaderBase {
+public:
+ ~AidlCommandReader();
+
+ // Parse and execute commands from the command queue. The commands are
+ // actually return values from the server and will be saved in ReturnData.
+ int parse();
+
+ // Get and clear saved errors.
+ struct CommandError {
+ uint32_t location;
+ Error error;
+ };
+ std::vector<CommandError> takeErrors();
+
+ bool hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
+ uint32_t* outNumLayerRequestMasks) const;
+
+ // Get and clear saved changed composition types.
+ void takeChangedCompositionTypes(Display display, std::vector<Layer>* outLayers,
+ std::vector<IComposerClient::Composition>* outTypes);
+
+ // Get and clear saved display requests.
+ void takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outLayers,
+ std::vector<uint32_t>* outLayerRequestMasks);
+
+ // Get and clear saved release fences.
+ void takeReleaseFences(Display display, std::vector<Layer>* outLayers,
+ std::vector<int>* outReleaseFences);
+
+ // Get and clear saved present fence.
+ void takePresentFence(Display display, int* outPresentFence);
+
+ // Get what stage succeeded during PresentOrValidate: Present or Validate
+ void takePresentOrValidateStage(Display display, uint32_t* state);
+
+ // Get the client target properties requested by hardware composer.
+ void takeClientTargetProperty(Display display,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty);
+
+private:
+ void resetData();
+
+ bool parseSelectDisplay(uint16_t length);
+ bool parseSetError(uint16_t length);
+ bool parseSetChangedCompositionTypes(uint16_t length);
+ bool parseSetDisplayRequests(uint16_t length);
+ bool parseSetPresentFence(uint16_t length);
+ bool parseSetReleaseFences(uint16_t length);
+ bool parseSetPresentOrValidateDisplayResult(uint16_t length);
+ bool parseSetClientTargetProperty(uint16_t length);
+
+ struct ReturnData {
+ uint32_t displayRequests = 0;
+
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+
+ int presentFence = -1;
+
+ std::vector<Layer> releasedLayers;
+ std::vector<int> releaseFences;
+
+ uint32_t presentOrValidateState;
+
+ // Composer 2.4 implementation can return a client target property
+ // structure to indicate the client target properties that hardware
+ // composer requests. The composer client must change the client target
+ // properties to match this request.
+ IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
+ Dataspace::UNKNOWN};
+ };
+
+ std::vector<CommandError> mErrors;
+ std::unordered_map<Display, ReturnData> mReturnData;
+
+ // When SELECT_DISPLAY is parsed, this is updated to point to the
+ // display's return data in mReturnData. We use it to avoid repeated
+ // map lookups.
+ ReturnData* mCurrentReturnData;
+};
+
+// Composer is a wrapper to IComposer, a proxy to server-side composer.
+class AidlComposer final : public Hwc2::Composer {
+public:
+ static bool isDeclared(const std::string& serviceName);
+
+ explicit AidlComposer(const std::string& serviceName);
+ ~AidlComposer() override;
+
+ std::vector<IComposer::Capability> getCapabilities() override;
+ std::string dumpDebugInfo() override;
+
+ void registerCallback(const sp<IComposerCallback>& callback) override;
+
+ // Reset all pending commands in the command buffer. Useful if you want to
+ // skip a frame but have already queued some commands.
+ void resetCommands() override;
+
+ // Explicitly flush all pending commands in the command buffer.
+ Error executeCommands() override;
+
+ uint32_t getMaxVirtualDisplayCount() override;
+ Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+ Display* outDisplay) override;
+ Error destroyVirtualDisplay(Display display) override;
+
+ Error acceptDisplayChanges(Display display) override;
+
+ Error createLayer(Display display, Layer* outLayer) override;
+ Error destroyLayer(Display display, Layer layer) override;
+
+ Error getActiveConfig(Display display, Config* outConfig) override;
+ Error getChangedCompositionTypes(Display display, std::vector<Layer>* outLayers,
+ std::vector<IComposerClient::Composition>* outTypes) override;
+ Error getColorModes(Display display, std::vector<ColorMode>* outModes) override;
+ Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
+ int32_t* outValue) override;
+ Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs);
+ Error getDisplayName(Display display, std::string* outName) override;
+
+ Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outLayers,
+ std::vector<uint32_t>* outLayerRequestMasks) override;
+
+ Error getDozeSupport(Display display, bool* outSupport) override;
+ Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
+ float* outMaxAverageLuminance, float* outMinLuminance) override;
+
+ Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
+ std::vector<int>* outReleaseFences) override;
+
+ Error presentDisplay(Display display, int* outPresentFence) override;
+
+ Error setActiveConfig(Display display, Config config) override;
+
+ /*
+ * The composer caches client targets internally. When target is nullptr,
+ * the composer uses slot to look up the client target from its cache.
+ * When target is not nullptr, the cache is updated with the new target.
+ */
+ Error setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
+ int acquireFence, Dataspace dataspace,
+ const std::vector<IComposerClient::Rect>& damage) override;
+ Error setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) override;
+ Error setColorTransform(Display display, const float* matrix, ColorTransform hint) override;
+ Error setOutputBuffer(Display display, const native_handle_t* buffer,
+ int releaseFence) override;
+ Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
+ Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
+
+ Error setClientTargetSlotCount(Display display) override;
+
+ Error validateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests) override;
+
+ Error presentOrValidateDisplay(Display display, uint32_t* outNumTypes, uint32_t* outNumRequests,
+ int* outPresentFence, uint32_t* state) override;
+
+ Error setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
+ /* see setClientTarget for the purpose of slot */
+ Error setLayerBuffer(Display display, Layer layer, uint32_t slot,
+ const sp<GraphicBuffer>& buffer, int acquireFence) override;
+ Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& damage) override;
+ Error setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) override;
+ Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) override;
+ Error setLayerCompositionType(Display display, Layer layer,
+ IComposerClient::Composition type) override;
+ Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) override;
+ Error setLayerDisplayFrame(Display display, Layer layer,
+ const IComposerClient::Rect& frame) override;
+ Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
+ Error setLayerSidebandStream(Display display, Layer layer,
+ const native_handle_t* stream) override;
+ Error setLayerSourceCrop(Display display, Layer layer,
+ const IComposerClient::FRect& crop) override;
+ Error setLayerTransform(Display display, Layer layer, Transform transform) override;
+ Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& visible) override;
+ Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+
+ // Composer HAL 2.2
+ Error setLayerPerFrameMetadata(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) override;
+ std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(
+ Display display) override;
+ Error getRenderIntents(Display display, ColorMode colorMode,
+ std::vector<RenderIntent>* outRenderIntents) override;
+ Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) override;
+
+ // Composer HAL 2.3
+ Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) override;
+ Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override;
+ Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace,
+ uint8_t* outComponentMask) override;
+ Error setDisplayContentSamplingEnabled(Display display, bool enabled, uint8_t componentMask,
+ uint64_t maxFrames) override;
+ Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
+ DisplayedFrameStats* outStats) override;
+ Error setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
+ Error setDisplayBrightness(Display display, float brightness) override;
+
+ // Composer HAL 2.4
+ bool isVsyncPeriodSwitchSupported() override { return true; }
+ Error getDisplayCapabilities(Display display,
+ std::vector<DisplayCapability>* outCapabilities) override;
+ V2_4::Error getDisplayConnectionType(Display display,
+ IComposerClient::DisplayConnectionType* outType) override;
+ V2_4::Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override;
+ V2_4::Error setActiveConfigWithConstraints(
+ Display display, Config config,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ VsyncPeriodChangeTimeline* outTimeline) override;
+ V2_4::Error setAutoLowLatencyMode(Display displayId, bool on) override;
+ V2_4::Error getSupportedContentTypes(
+ Display displayId,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
+ V2_4::Error setContentType(Display displayId,
+ IComposerClient::ContentType contentType) override;
+ V2_4::Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ 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) override;
+
+private:
+ class AidlCommandWriter : public AidlCommandWriterBase {
+ public:
+ explicit AidlCommandWriter(uint32_t initialMaxSize)
+ : AidlCommandWriterBase(initialMaxSize) {}
+ ~AidlCommandWriter() override {}
+ };
+
+ // Many public functions above simply write a command into the command
+ // queue to batch the calls. validateDisplay and presentDisplay will call
+ // this function to execute the command queue.
+ Error execute();
+
+ // returns the default instance name for the given service
+ static std::string instance(const std::string& serviceName);
+
+ // 64KiB minus a small space for metadata such as read/write pointers
+ static constexpr size_t kWriterInitialSize = 64 * 1024 / sizeof(uint32_t) - 16;
+ // Max number of buffers that may be cached for a given layer
+ // We obtain this number by:
+ // 1. Tightly coupling this cache to the max size of BufferQueue
+ // 2. Adding an additional slot for the layer caching feature in SurfaceFlinger (see: Planner.h)
+ static const constexpr uint32_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
+ AidlCommandWriter mWriter;
+ AidlCommandReader mReader;
+
+ // Aidl interface
+ using AidlIComposer = aidl::android::hardware::graphics::composer3::IComposer;
+ using AidlIComposerClient = aidl::android::hardware::graphics::composer3::IComposerClient;
+ std::shared_ptr<AidlIComposer> mAidlComposer;
+ std::shared_ptr<AidlIComposerClient> mAidlComposerClient;
+ std::shared_ptr<AidlIComposerCallbackWrapper> mAidlComposerCallback;
+};
+
+} // namespace android::Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 09734c2..d69a923 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -14,1562 +14,23 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#undef LOG_TAG
#define LOG_TAG "HwcComposer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "ComposerHal.h"
+#include "AidlComposerHal.h"
+#include "HidlComposerHal.h"
-#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
-#include <hidl/HidlTransportSupport.h>
-#include <hidl/HidlTransportUtils.h>
-#include <log/log.h>
-#include <utils/Trace.h>
-
-#include <algorithm>
-#include <cinttypes>
-
-namespace android {
-
-using hardware::Return;
-using hardware::hidl_vec;
-using hardware::hidl_handle;
-
-namespace Hwc2 {
+namespace android::Hwc2 {
Composer::~Composer() = default;
-namespace {
-
-class BufferHandle {
-public:
- explicit BufferHandle(const native_handle_t* buffer) {
- // nullptr is not a valid handle to HIDL
- mHandle = (buffer) ? buffer : native_handle_init(mStorage, 0, 0);
+std::unique_ptr<Composer> Composer::create(const std::string& serviceName) {
+ if (AidlComposer::isDeclared(serviceName)) {
+ return std::make_unique<AidlComposer>(serviceName);
}
- operator const hidl_handle&() const // NOLINT(google-explicit-constructor)
- {
- return mHandle;
- }
-
-private:
- NATIVE_HANDLE_DECLARE_STORAGE(mStorage, 0, 0);
- hidl_handle mHandle;
-};
-
-class FenceHandle
-{
-public:
- FenceHandle(int fd, bool owned)
- : mOwned(owned)
- {
- native_handle_t* handle;
- if (fd >= 0) {
- handle = native_handle_init(mStorage, 1, 0);
- handle->data[0] = fd;
- } else {
- // nullptr is not a valid handle to HIDL
- handle = native_handle_init(mStorage, 0, 0);
- }
- mHandle = handle;
- }
-
- ~FenceHandle()
- {
- if (mOwned) {
- native_handle_close(mHandle);
- }
- }
-
- operator const hidl_handle&() const // NOLINT(google-explicit-constructor)
- {
- return mHandle;
- }
-
-private:
- bool mOwned;
- NATIVE_HANDLE_DECLARE_STORAGE(mStorage, 1, 0);
- hidl_handle mHandle;
-};
-
-// assume NO_RESOURCES when Status::isOk returns false
-constexpr Error kDefaultError = Error::NO_RESOURCES;
-constexpr V2_4::Error kDefaultError_2_4 = static_cast<V2_4::Error>(kDefaultError);
-
-template<typename T, typename U>
-T unwrapRet(Return<T>& ret, const U& default_val)
-{
- return (ret.isOk()) ? static_cast<T>(ret) :
- static_cast<T>(default_val);
+ return std::make_unique<HidlComposer>(serviceName);
}
-Error unwrapRet(Return<Error>& ret)
-{
- return unwrapRet(ret, kDefaultError);
-}
-
-} // anonymous namespace
-
-namespace impl {
-
-Composer::Composer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
- mComposer = V2_1::IComposer::getService(serviceName);
-
- if (mComposer == nullptr) {
- LOG_ALWAYS_FATAL("failed to get hwcomposer service");
- }
-
- if (sp<IComposer> composer_2_4 = IComposer::castFrom(mComposer)) {
- composer_2_4->createClient_2_4([&](const auto& tmpError, const auto& tmpClient) {
- if (tmpError == V2_4::Error::NONE) {
- mClient = tmpClient;
- mClient_2_2 = tmpClient;
- mClient_2_3 = tmpClient;
- mClient_2_4 = tmpClient;
- }
- });
- } else if (sp<V2_3::IComposer> composer_2_3 = V2_3::IComposer::castFrom(mComposer)) {
- composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) {
- if (tmpError == Error::NONE) {
- mClient = tmpClient;
- mClient_2_2 = tmpClient;
- mClient_2_3 = tmpClient;
- }
- });
- } else {
- mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
- if (tmpError != Error::NONE) {
- return;
- }
-
- mClient = tmpClient;
- if (sp<V2_2::IComposer> composer_2_2 = V2_2::IComposer::castFrom(mComposer)) {
- mClient_2_2 = V2_2::IComposerClient::castFrom(mClient);
- LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr,
- "IComposer 2.2 did not return IComposerClient 2.2");
- }
- });
- }
-
- if (mClient == nullptr) {
- LOG_ALWAYS_FATAL("failed to create composer client");
- }
-}
-
-Composer::~Composer() = default;
-
-std::vector<IComposer::Capability> Composer::getCapabilities()
-{
- std::vector<IComposer::Capability> capabilities;
- mComposer->getCapabilities(
- [&](const auto& tmpCapabilities) {
- capabilities = tmpCapabilities;
- });
- return capabilities;
-}
-
-std::string Composer::dumpDebugInfo()
-{
- std::string info;
- mComposer->dumpDebugInfo([&](const auto& tmpInfo) {
- info = tmpInfo.c_str();
- });
-
- return info;
-}
-
-void Composer::registerCallback(const sp<IComposerCallback>& callback)
-{
- android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
- auto ret = [&]() {
- if (mClient_2_4) {
- return mClient_2_4->registerCallback_2_4(callback);
- }
- return mClient->registerCallback(callback);
- }();
- if (!ret.isOk()) {
- ALOGE("failed to register IComposerCallback");
- }
-}
-
-void Composer::resetCommands() {
- mWriter.reset();
-}
-
-Error Composer::executeCommands() {
- return execute();
-}
-
-uint32_t Composer::getMaxVirtualDisplayCount()
-{
- auto ret = mClient->getMaxVirtualDisplayCount();
- return unwrapRet(ret, 0);
-}
-
-Error Composer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
- Display* outDisplay) {
- const uint32_t bufferSlotCount = 1;
- Error error = kDefaultError;
- if (mClient_2_2) {
- mClient_2_2->createVirtualDisplay_2_2(width, height,
- static_cast<types::V1_1::PixelFormat>(*format),
- bufferSlotCount,
- [&](const auto& tmpError, const auto& tmpDisplay,
- const auto& tmpFormat) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outDisplay = tmpDisplay;
- *format = static_cast<types::V1_2::PixelFormat>(
- tmpFormat);
- });
- } else {
- mClient->createVirtualDisplay(width, height,
- static_cast<types::V1_0::PixelFormat>(*format), bufferSlotCount,
- [&](const auto& tmpError, const auto& tmpDisplay,
- const auto& tmpFormat) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outDisplay = tmpDisplay;
- *format = static_cast<PixelFormat>(tmpFormat);
- });
- }
-
- return error;
-}
-
-Error Composer::destroyVirtualDisplay(Display display)
-{
- auto ret = mClient->destroyVirtualDisplay(display);
- return unwrapRet(ret);
-}
-
-Error Composer::acceptDisplayChanges(Display display)
-{
- mWriter.selectDisplay(display);
- mWriter.acceptDisplayChanges();
- return Error::NONE;
-}
-
-Error Composer::createLayer(Display display, Layer* outLayer)
-{
- Error error = kDefaultError;
- mClient->createLayer(display, kMaxLayerBufferCount,
- [&](const auto& tmpError, const auto& tmpLayer) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outLayer = tmpLayer;
- });
-
- return error;
-}
-
-Error Composer::destroyLayer(Display display, Layer layer)
-{
- auto ret = mClient->destroyLayer(display, layer);
- return unwrapRet(ret);
-}
-
-Error Composer::getActiveConfig(Display display, Config* outConfig)
-{
- Error error = kDefaultError;
- mClient->getActiveConfig(display,
- [&](const auto& tmpError, const auto& tmpConfig) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outConfig = tmpConfig;
- });
-
- return error;
-}
-
-Error Composer::getChangedCompositionTypes(Display display,
- std::vector<Layer>* outLayers,
- std::vector<IComposerClient::Composition>* outTypes)
-{
- mReader.takeChangedCompositionTypes(display, outLayers, outTypes);
- return Error::NONE;
-}
-
-Error Composer::getColorModes(Display display,
- std::vector<ColorMode>* outModes)
-{
- Error error = kDefaultError;
-
- if (mClient_2_3) {
- mClient_2_3->getColorModes_2_3(display, [&](const auto& tmpError, const auto& tmpModes) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outModes = tmpModes;
- });
- } else if (mClient_2_2) {
- mClient_2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- for (types::V1_1::ColorMode colorMode : tmpModes) {
- outModes->push_back(static_cast<ColorMode>(colorMode));
- }
- });
- } else {
- mClient->getColorModes(display,
- [&](const auto& tmpError, const auto& tmpModes) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
- for (types::V1_0::ColorMode colorMode : tmpModes) {
- outModes->push_back(static_cast<ColorMode>(colorMode));
- }
- });
- }
-
- return error;
-}
-
-Error Composer::getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute, int32_t* outValue)
-{
- Error error = kDefaultError;
- if (mClient_2_4) {
- mClient_2_4->getDisplayAttribute_2_4(display, config, attribute,
- [&](const auto& tmpError, const auto& tmpValue) {
- error = static_cast<Error>(tmpError);
- if (error != Error::NONE) {
- return;
- }
-
- *outValue = tmpValue;
- });
- } else {
- mClient->getDisplayAttribute(display, config,
- static_cast<V2_1::IComposerClient::Attribute>(attribute),
- [&](const auto& tmpError, const auto& tmpValue) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outValue = tmpValue;
- });
- }
-
- return error;
-}
-
-Error Composer::getDisplayConfigs(Display display,
- std::vector<Config>* outConfigs)
-{
- Error error = kDefaultError;
- mClient->getDisplayConfigs(display,
- [&](const auto& tmpError, const auto& tmpConfigs) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outConfigs = tmpConfigs;
- });
-
- return error;
-}
-
-Error Composer::getDisplayName(Display display, std::string* outName)
-{
- Error error = kDefaultError;
- mClient->getDisplayName(display,
- [&](const auto& tmpError, const auto& tmpName) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outName = tmpName.c_str();
- });
-
- return error;
-}
-
-Error Composer::getDisplayRequests(Display display,
- uint32_t* outDisplayRequestMask, std::vector<Layer>* outLayers,
- std::vector<uint32_t>* outLayerRequestMasks)
-{
- mReader.takeDisplayRequests(display, outDisplayRequestMask,
- outLayers, outLayerRequestMasks);
- return Error::NONE;
-}
-
-Error Composer::getDozeSupport(Display display, bool* outSupport)
-{
- Error error = kDefaultError;
- mClient->getDozeSupport(display,
- [&](const auto& tmpError, const auto& tmpSupport) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outSupport = tmpSupport;
- });
-
- return error;
-}
-
-Error Composer::getHdrCapabilities(Display display,
- std::vector<Hdr>* outTypes, float* outMaxLuminance,
- float* outMaxAverageLuminance, float* outMinLuminance)
-{
- Error error = kDefaultError;
- if (mClient_2_3) {
- mClient_2_3->getHdrCapabilities_2_3(display,
- [&](const auto& tmpError, const auto& tmpTypes,
- const auto& tmpMaxLuminance,
- const auto& tmpMaxAverageLuminance,
- const auto& tmpMinLuminance) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outTypes = tmpTypes;
- *outMaxLuminance = tmpMaxLuminance;
- *outMaxAverageLuminance = tmpMaxAverageLuminance;
- *outMinLuminance = tmpMinLuminance;
- });
- } else {
- mClient->getHdrCapabilities(display,
- [&](const auto& tmpError, const auto& tmpTypes,
- const auto& tmpMaxLuminance,
- const auto& tmpMaxAverageLuminance,
- const auto& tmpMinLuminance) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- outTypes->clear();
- for (auto type : tmpTypes) {
- outTypes->push_back(static_cast<Hdr>(type));
- }
-
- *outMaxLuminance = tmpMaxLuminance;
- *outMaxAverageLuminance = tmpMaxAverageLuminance;
- *outMinLuminance = tmpMinLuminance;
- });
- }
-
- return error;
-}
-
-Error Composer::getReleaseFences(Display display,
- std::vector<Layer>* outLayers, std::vector<int>* outReleaseFences)
-{
- mReader.takeReleaseFences(display, outLayers, outReleaseFences);
- return Error::NONE;
-}
-
-Error Composer::presentDisplay(Display display, int* outPresentFence)
-{
- ATRACE_NAME("HwcPresentDisplay");
- mWriter.selectDisplay(display);
- mWriter.presentDisplay();
-
- Error error = execute();
- if (error != Error::NONE) {
- return error;
- }
-
- mReader.takePresentFence(display, outPresentFence);
-
- return Error::NONE;
-}
-
-Error Composer::setActiveConfig(Display display, Config config)
-{
- auto ret = mClient->setActiveConfig(display, config);
- return unwrapRet(ret);
-}
-
-Error Composer::setClientTarget(Display display, uint32_t slot,
- const sp<GraphicBuffer>& target,
- int acquireFence, Dataspace dataspace,
- const std::vector<IComposerClient::Rect>& damage)
-{
- mWriter.selectDisplay(display);
-
- const native_handle_t* handle = nullptr;
- if (target.get()) {
- handle = target->getNativeBuffer()->handle;
- }
-
- mWriter.setClientTarget(slot, handle, acquireFence, dataspace, damage);
- return Error::NONE;
-}
-
-Error Composer::setColorMode(Display display, ColorMode mode,
- RenderIntent renderIntent)
-{
- hardware::Return<Error> ret(kDefaultError);
- if (mClient_2_3) {
- ret = mClient_2_3->setColorMode_2_3(display, mode, renderIntent);
- } else if (mClient_2_2) {
- ret = mClient_2_2->setColorMode_2_2(display, static_cast<types::V1_1::ColorMode>(mode),
- renderIntent);
- } else {
- ret = mClient->setColorMode(display,
- static_cast<types::V1_0::ColorMode>(mode));
- }
- return unwrapRet(ret);
-}
-
-Error Composer::setColorTransform(Display display, const float* matrix,
- ColorTransform hint)
-{
- mWriter.selectDisplay(display);
- mWriter.setColorTransform(matrix, hint);
- return Error::NONE;
-}
-
-Error Composer::setOutputBuffer(Display display, const native_handle_t* buffer,
- int releaseFence)
-{
- mWriter.selectDisplay(display);
- mWriter.setOutputBuffer(0, buffer, dup(releaseFence));
- return Error::NONE;
-}
-
-Error Composer::setPowerMode(Display display, IComposerClient::PowerMode mode) {
- Return<Error> ret(Error::UNSUPPORTED);
- if (mClient_2_2) {
- ret = mClient_2_2->setPowerMode_2_2(display, mode);
- } else if (mode != IComposerClient::PowerMode::ON_SUSPEND) {
- ret = mClient->setPowerMode(display, static_cast<V2_1::IComposerClient::PowerMode>(mode));
- }
-
- return unwrapRet(ret);
-}
-
-Error Composer::setVsyncEnabled(Display display, IComposerClient::Vsync enabled)
-{
- auto ret = mClient->setVsyncEnabled(display, enabled);
- return unwrapRet(ret);
-}
-
-Error Composer::setClientTargetSlotCount(Display display)
-{
- const uint32_t bufferSlotCount = BufferQueue::NUM_BUFFER_SLOTS;
- auto ret = mClient->setClientTargetSlotCount(display, bufferSlotCount);
- return unwrapRet(ret);
-}
-
-Error Composer::validateDisplay(Display display, uint32_t* outNumTypes,
- uint32_t* outNumRequests)
-{
- ATRACE_NAME("HwcValidateDisplay");
- mWriter.selectDisplay(display);
- mWriter.validateDisplay();
-
- Error error = execute();
- if (error != Error::NONE) {
- return error;
- }
-
- mReader.hasChanges(display, outNumTypes, outNumRequests);
-
- return Error::NONE;
-}
-
-Error Composer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
- uint32_t* outNumRequests, int* outPresentFence, uint32_t* state) {
- ATRACE_NAME("HwcPresentOrValidateDisplay");
- mWriter.selectDisplay(display);
- mWriter.presentOrvalidateDisplay();
-
- Error error = execute();
- if (error != Error::NONE) {
- return error;
- }
-
- mReader.takePresentOrValidateStage(display, state);
-
- if (*state == 1) { // Present succeeded
- mReader.takePresentFence(display, outPresentFence);
- }
-
- if (*state == 0) { // Validate succeeded.
- mReader.hasChanges(display, outNumTypes, outNumRequests);
- }
-
- return Error::NONE;
-}
-
-Error Composer::setCursorPosition(Display display, Layer layer,
- int32_t x, int32_t y)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerCursorPosition(x, y);
- return Error::NONE;
-}
-
-Error Composer::setLayerBuffer(Display display, Layer layer,
- uint32_t slot, const sp<GraphicBuffer>& buffer, int acquireFence)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
-
- const native_handle_t* handle = nullptr;
- if (buffer.get()) {
- handle = buffer->getNativeBuffer()->handle;
- }
-
- mWriter.setLayerBuffer(slot, handle, acquireFence);
- return Error::NONE;
-}
-
-Error Composer::setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<IComposerClient::Rect>& damage)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerSurfaceDamage(damage);
- return Error::NONE;
-}
-
-Error Composer::setLayerBlendMode(Display display, Layer layer,
- IComposerClient::BlendMode mode)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerBlendMode(mode);
- return Error::NONE;
-}
-
-Error Composer::setLayerColor(Display display, Layer layer,
- const IComposerClient::Color& color)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerColor(color);
- return Error::NONE;
-}
-
-Error Composer::setLayerCompositionType(Display display, Layer layer,
- IComposerClient::Composition type)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerCompositionType(type);
- return Error::NONE;
-}
-
-Error Composer::setLayerDataspace(Display display, Layer layer,
- Dataspace dataspace)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerDataspace(dataspace);
- return Error::NONE;
-}
-
-Error Composer::setLayerDisplayFrame(Display display, Layer layer,
- const IComposerClient::Rect& frame)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerDisplayFrame(frame);
- return Error::NONE;
-}
-
-Error Composer::setLayerPlaneAlpha(Display display, Layer layer,
- float alpha)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerPlaneAlpha(alpha);
- return Error::NONE;
-}
-
-Error Composer::setLayerSidebandStream(Display display, Layer layer,
- const native_handle_t* stream)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerSidebandStream(stream);
- return Error::NONE;
-}
-
-Error Composer::setLayerSourceCrop(Display display, Layer layer,
- const IComposerClient::FRect& crop)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerSourceCrop(crop);
- return Error::NONE;
-}
-
-Error Composer::setLayerTransform(Display display, Layer layer,
- Transform transform)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerTransform(transform);
- return Error::NONE;
-}
-
-Error Composer::setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<IComposerClient::Rect>& visible)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerVisibleRegion(visible);
- return Error::NONE;
-}
-
-Error Composer::setLayerZOrder(Display display, Layer layer, uint32_t z)
-{
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerZOrder(z);
- return Error::NONE;
-}
-
-Error Composer::execute()
-{
- // prepare input command queue
- bool queueChanged = false;
- uint32_t commandLength = 0;
- hidl_vec<hidl_handle> commandHandles;
- if (!mWriter.writeQueue(&queueChanged, &commandLength, &commandHandles)) {
- mWriter.reset();
- return Error::NO_RESOURCES;
- }
-
- // set up new input command queue if necessary
- if (queueChanged) {
- auto ret = mClient->setInputCommandQueue(*mWriter.getMQDescriptor());
- auto error = unwrapRet(ret);
- if (error != Error::NONE) {
- mWriter.reset();
- return error;
- }
- }
-
- if (commandLength == 0) {
- mWriter.reset();
- return Error::NONE;
- }
-
- Error error = kDefaultError;
- hardware::Return<void> ret;
- auto hidl_callback = [&](const auto& tmpError, const auto& tmpOutChanged,
- const auto& tmpOutLength, const auto& tmpOutHandles)
- {
- error = tmpError;
-
- // set up new output command queue if necessary
- if (error == Error::NONE && tmpOutChanged) {
- error = kDefaultError;
- mClient->getOutputCommandQueue(
- [&](const auto& tmpError,
- const auto& tmpDescriptor)
- {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- mReader.setMQDescriptor(tmpDescriptor);
- });
- }
-
- if (error != Error::NONE) {
- return;
- }
-
- if (mReader.readQueue(tmpOutLength, tmpOutHandles)) {
- error = mReader.parse();
- mReader.reset();
- } else {
- error = Error::NO_RESOURCES;
- }
- };
- if (mClient_2_2) {
- ret = mClient_2_2->executeCommands_2_2(commandLength, commandHandles, hidl_callback);
- } else {
- ret = mClient->executeCommands(commandLength, commandHandles, hidl_callback);
- }
- // executeCommands can fail because of out-of-fd and we do not want to
- // abort() in that case
- if (!ret.isOk()) {
- ALOGE("executeCommands failed because of %s", ret.description().c_str());
- }
-
- if (error == Error::NONE) {
- std::vector<CommandReader::CommandError> commandErrors =
- mReader.takeErrors();
-
- for (const auto& cmdErr : commandErrors) {
- auto command =
- static_cast<IComposerClient::Command>(mWriter.getCommand(cmdErr.location));
-
- if (command == IComposerClient::Command::VALIDATE_DISPLAY ||
- command == IComposerClient::Command::PRESENT_DISPLAY ||
- command == IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY) {
- error = cmdErr.error;
- } else {
- ALOGW("command 0x%x generated error %d",
- command, cmdErr.error);
- }
- }
- }
-
- mWriter.reset();
-
- return error;
-}
-
-// Composer HAL 2.2
-
-Error Composer::setLayerPerFrameMetadata(Display display, Layer layer,
- const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) {
- if (!mClient_2_2) {
- return Error::UNSUPPORTED;
- }
-
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerPerFrameMetadata(perFrameMetadatas);
- return Error::NONE;
-}
-
-std::vector<IComposerClient::PerFrameMetadataKey> Composer::getPerFrameMetadataKeys(
- Display display) {
- std::vector<IComposerClient::PerFrameMetadataKey> keys;
- if (!mClient_2_2) {
- return keys;
- }
-
- Error error = kDefaultError;
- if (mClient_2_3) {
- mClient_2_3->getPerFrameMetadataKeys_2_3(display,
- [&](const auto& tmpError, const auto& tmpKeys) {
- error = tmpError;
- if (error != Error::NONE) {
- ALOGW("getPerFrameMetadataKeys failed "
- "with %d",
- tmpError);
- return;
- }
- keys = tmpKeys;
- });
- } else {
- mClient_2_2
- ->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
- error = tmpError;
- if (error != Error::NONE) {
- ALOGW("getPerFrameMetadataKeys failed with %d", tmpError);
- return;
- }
-
- keys.clear();
- for (auto key : tmpKeys) {
- keys.push_back(static_cast<IComposerClient::PerFrameMetadataKey>(key));
- }
- });
- }
-
- return keys;
-}
-
-Error Composer::getRenderIntents(Display display, ColorMode colorMode,
- std::vector<RenderIntent>* outRenderIntents) {
- if (!mClient_2_2) {
- outRenderIntents->push_back(RenderIntent::COLORIMETRIC);
- return Error::NONE;
- }
-
- Error error = kDefaultError;
-
- auto getRenderIntentsLambda = [&](const auto& tmpError, const auto& tmpKeys) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outRenderIntents = tmpKeys;
- };
-
- if (mClient_2_3) {
- mClient_2_3->getRenderIntents_2_3(display, colorMode, getRenderIntentsLambda);
- } else {
- mClient_2_2->getRenderIntents(display, static_cast<types::V1_1::ColorMode>(colorMode),
- getRenderIntentsLambda);
- }
-
- return error;
-}
-
-Error Composer::getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix)
-{
- if (!mClient_2_2) {
- *outMatrix = mat4();
- return Error::NONE;
- }
-
- Error error = kDefaultError;
- mClient_2_2->getDataspaceSaturationMatrix(static_cast<types::V1_1::Dataspace>(dataspace),
- [&](const auto& tmpError, const auto& tmpMatrix) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
- *outMatrix = mat4(tmpMatrix.data());
- });
-
- return error;
-}
-
-// Composer HAL 2.3
-
-Error Composer::getDisplayIdentificationData(Display display, uint8_t* outPort,
- std::vector<uint8_t>* outData) {
- if (!mClient_2_3) {
- return Error::UNSUPPORTED;
- }
-
- Error error = kDefaultError;
- mClient_2_3->getDisplayIdentificationData(display,
- [&](const auto& tmpError, const auto& tmpPort,
- const auto& tmpData) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outPort = tmpPort;
- *outData = tmpData;
- });
-
- return error;
-}
-
-Error Composer::setLayerColorTransform(Display display, Layer layer, const float* matrix)
-{
- if (!mClient_2_3) {
- return Error::UNSUPPORTED;
- }
-
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerColorTransform(matrix);
- return Error::NONE;
-}
-
-Error Composer::getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
- Dataspace* outDataspace,
- uint8_t* outComponentMask) {
- if (!outFormat || !outDataspace || !outComponentMask) {
- return Error::BAD_PARAMETER;
- }
- if (!mClient_2_3) {
- return Error::UNSUPPORTED;
- }
- Error error = kDefaultError;
- mClient_2_3->getDisplayedContentSamplingAttributes(display,
- [&](const auto tmpError,
- const auto& tmpFormat,
- const auto& tmpDataspace,
- const auto& tmpComponentMask) {
- error = tmpError;
- if (error == Error::NONE) {
- *outFormat = tmpFormat;
- *outDataspace = tmpDataspace;
- *outComponentMask =
- static_cast<uint8_t>(
- tmpComponentMask);
- }
- });
- return error;
-}
-
-Error Composer::setDisplayContentSamplingEnabled(Display display, bool enabled,
- uint8_t componentMask, uint64_t maxFrames) {
- if (!mClient_2_3) {
- return Error::UNSUPPORTED;
- }
-
- auto enable = enabled ? V2_3::IComposerClient::DisplayedContentSampling::ENABLE
- : V2_3::IComposerClient::DisplayedContentSampling::DISABLE;
- return mClient_2_3->setDisplayedContentSamplingEnabled(display, enable, componentMask,
- maxFrames);
-}
-
-Error Composer::getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
- DisplayedFrameStats* outStats) {
- if (!outStats) {
- return Error::BAD_PARAMETER;
- }
- if (!mClient_2_3) {
- return Error::UNSUPPORTED;
- }
- Error error = kDefaultError;
- mClient_2_3->getDisplayedContentSample(display, maxFrames, timestamp,
- [&](const auto tmpError, auto tmpNumFrames,
- const auto& tmpSamples0, const auto& tmpSamples1,
- const auto& tmpSamples2, const auto& tmpSamples3) {
- error = tmpError;
- if (error == Error::NONE) {
- outStats->numFrames = tmpNumFrames;
- outStats->component_0_sample = tmpSamples0;
- outStats->component_1_sample = tmpSamples1;
- outStats->component_2_sample = tmpSamples2;
- outStats->component_3_sample = tmpSamples3;
- }
- });
- return error;
-}
-
-Error Composer::setLayerPerFrameMetadataBlobs(
- Display display, Layer layer,
- const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) {
- if (!mClient_2_3) {
- return Error::UNSUPPORTED;
- }
-
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerPerFrameMetadataBlobs(metadata);
- return Error::NONE;
-}
-
-Error Composer::setDisplayBrightness(Display display, float brightness) {
- if (!mClient_2_3) {
- return Error::UNSUPPORTED;
- }
- return mClient_2_3->setDisplayBrightness(display, brightness);
-}
-
-// Composer HAL 2.4
-
-Error Composer::getDisplayCapabilities(Display display,
- std::vector<DisplayCapability>* outCapabilities) {
- if (!mClient_2_3) {
- return Error::UNSUPPORTED;
- }
-
- V2_4::Error error = kDefaultError_2_4;
- if (mClient_2_4) {
- mClient_2_4->getDisplayCapabilities_2_4(display,
- [&](const auto& tmpError, const auto& tmpCaps) {
- error = tmpError;
- if (error != V2_4::Error::NONE) {
- return;
- }
- *outCapabilities = tmpCaps;
- });
- } else {
- mClient_2_3
- ->getDisplayCapabilities(display, [&](const auto& tmpError, const auto& tmpCaps) {
- error = static_cast<V2_4::Error>(tmpError);
- if (error != V2_4::Error::NONE) {
- return;
- }
-
- outCapabilities->resize(tmpCaps.size());
- std::transform(tmpCaps.begin(), tmpCaps.end(), outCapabilities->begin(),
- [](auto cap) { return static_cast<DisplayCapability>(cap); });
- });
- }
-
- return static_cast<Error>(error);
-}
-
-V2_4::Error Composer::getDisplayConnectionType(Display display,
- IComposerClient::DisplayConnectionType* outType) {
- using Error = V2_4::Error;
- if (!mClient_2_4) {
- return Error::UNSUPPORTED;
- }
-
- Error error = kDefaultError_2_4;
- mClient_2_4->getDisplayConnectionType(display, [&](const auto& tmpError, const auto& tmpType) {
- error = tmpError;
- if (error != V2_4::Error::NONE) {
- return;
- }
-
- *outType = tmpType;
- });
-
- return error;
-}
-
-V2_4::Error Composer::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) {
- using Error = V2_4::Error;
- if (!mClient_2_4) {
- return Error::UNSUPPORTED;
- }
-
- Error error = kDefaultError_2_4;
- mClient_2_4->getDisplayVsyncPeriod(display,
- [&](const auto& tmpError, const auto& tmpVsyncPeriod) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outVsyncPeriod = tmpVsyncPeriod;
- });
-
- return error;
-}
-
-V2_4::Error Composer::setActiveConfigWithConstraints(
- Display display, Config config,
- const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
- VsyncPeriodChangeTimeline* outTimeline) {
- using Error = V2_4::Error;
- if (!mClient_2_4) {
- return Error::UNSUPPORTED;
- }
-
- Error error = kDefaultError_2_4;
- mClient_2_4->setActiveConfigWithConstraints(display, config, vsyncPeriodChangeConstraints,
- [&](const auto& tmpError, const auto& tmpTimeline) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outTimeline = tmpTimeline;
- });
-
- return error;
-}
-
-V2_4::Error Composer::setAutoLowLatencyMode(Display display, bool on) {
- using Error = V2_4::Error;
- if (!mClient_2_4) {
- return Error::UNSUPPORTED;
- }
-
- return mClient_2_4->setAutoLowLatencyMode(display, on);
-}
-
-V2_4::Error Composer::getSupportedContentTypes(
- Display displayId, std::vector<IComposerClient::ContentType>* outSupportedContentTypes) {
- using Error = V2_4::Error;
- if (!mClient_2_4) {
- return Error::UNSUPPORTED;
- }
-
- Error error = kDefaultError_2_4;
- mClient_2_4->getSupportedContentTypes(displayId,
- [&](const auto& tmpError,
- const auto& tmpSupportedContentTypes) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outSupportedContentTypes = tmpSupportedContentTypes;
- });
- return error;
-}
-
-V2_4::Error Composer::setContentType(Display display, IComposerClient::ContentType contentType) {
- using Error = V2_4::Error;
- if (!mClient_2_4) {
- return Error::UNSUPPORTED;
- }
-
- return mClient_2_4->setContentType(display, contentType);
-}
-
-V2_4::Error Composer::setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
- bool mandatory, const std::vector<uint8_t>& value) {
- using Error = V2_4::Error;
- if (!mClient_2_4) {
- return Error::UNSUPPORTED;
- }
- mWriter.selectDisplay(display);
- mWriter.selectLayer(layer);
- mWriter.setLayerGenericMetadata(key, mandatory, value);
- return Error::NONE;
-}
-
-V2_4::Error Composer::getLayerGenericMetadataKeys(
- std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
- using Error = V2_4::Error;
- if (!mClient_2_4) {
- return Error::UNSUPPORTED;
- }
- Error error = kDefaultError_2_4;
- mClient_2_4->getLayerGenericMetadataKeys([&](const auto& tmpError, const auto& tmpKeys) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
-
- *outKeys = tmpKeys;
- });
- return error;
-}
-
-Error Composer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
- mReader.takeClientTargetProperty(display, outClientTargetProperty);
- return Error::NONE;
-}
-
-CommandReader::~CommandReader()
-{
- resetData();
-}
-
-Error CommandReader::parse()
-{
- resetData();
-
- IComposerClient::Command command;
- uint16_t length = 0;
-
- while (!isEmpty()) {
- if (!beginCommand(&command, &length)) {
- break;
- }
-
- bool parsed = false;
- switch (command) {
- case IComposerClient::Command::SELECT_DISPLAY:
- parsed = parseSelectDisplay(length);
- break;
- case IComposerClient::Command::SET_ERROR:
- parsed = parseSetError(length);
- break;
- case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
- parsed = parseSetChangedCompositionTypes(length);
- break;
- case IComposerClient::Command::SET_DISPLAY_REQUESTS:
- parsed = parseSetDisplayRequests(length);
- break;
- case IComposerClient::Command::SET_PRESENT_FENCE:
- parsed = parseSetPresentFence(length);
- break;
- case IComposerClient::Command::SET_RELEASE_FENCES:
- parsed = parseSetReleaseFences(length);
- break;
- case IComposerClient::Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
- parsed = parseSetPresentOrValidateDisplayResult(length);
- break;
- case IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY:
- parsed = parseSetClientTargetProperty(length);
- break;
- default:
- parsed = false;
- break;
- }
-
- endCommand();
-
- if (!parsed) {
- ALOGE("failed to parse command 0x%x length %" PRIu16,
- command, length);
- break;
- }
- }
-
- return isEmpty() ? Error::NONE : Error::NO_RESOURCES;
-}
-
-bool CommandReader::parseSelectDisplay(uint16_t length)
-{
- if (length != CommandWriterBase::kSelectDisplayLength) {
- return false;
- }
-
- mCurrentReturnData = &mReturnData[read64()];
-
- return true;
-}
-
-bool CommandReader::parseSetError(uint16_t length)
-{
- if (length != CommandWriterBase::kSetErrorLength) {
- return false;
- }
-
- auto location = read();
- auto error = static_cast<Error>(readSigned());
-
- mErrors.emplace_back(CommandError{location, error});
-
- return true;
-}
-
-bool CommandReader::parseSetChangedCompositionTypes(uint16_t length)
-{
- // (layer id, composition type) pairs
- if (length % 3 != 0 || !mCurrentReturnData) {
- return false;
- }
-
- uint32_t count = length / 3;
- mCurrentReturnData->changedLayers.reserve(count);
- mCurrentReturnData->compositionTypes.reserve(count);
- while (count > 0) {
- auto layer = read64();
- auto type = static_cast<IComposerClient::Composition>(readSigned());
-
- mCurrentReturnData->changedLayers.push_back(layer);
- mCurrentReturnData->compositionTypes.push_back(type);
-
- count--;
- }
-
- return true;
-}
-
-bool CommandReader::parseSetDisplayRequests(uint16_t length)
-{
- // display requests followed by (layer id, layer requests) pairs
- if (length % 3 != 1 || !mCurrentReturnData) {
- return false;
- }
-
- mCurrentReturnData->displayRequests = read();
-
- uint32_t count = (length - 1) / 3;
- mCurrentReturnData->requestedLayers.reserve(count);
- mCurrentReturnData->requestMasks.reserve(count);
- while (count > 0) {
- auto layer = read64();
- auto layerRequestMask = read();
-
- mCurrentReturnData->requestedLayers.push_back(layer);
- mCurrentReturnData->requestMasks.push_back(layerRequestMask);
-
- count--;
- }
-
- return true;
-}
-
-bool CommandReader::parseSetPresentFence(uint16_t length)
-{
- if (length != CommandWriterBase::kSetPresentFenceLength ||
- !mCurrentReturnData) {
- return false;
- }
-
- if (mCurrentReturnData->presentFence >= 0) {
- close(mCurrentReturnData->presentFence);
- }
- mCurrentReturnData->presentFence = readFence();
-
- return true;
-}
-
-bool CommandReader::parseSetReleaseFences(uint16_t length)
-{
- // (layer id, release fence index) pairs
- if (length % 3 != 0 || !mCurrentReturnData) {
- return false;
- }
-
- uint32_t count = length / 3;
- mCurrentReturnData->releasedLayers.reserve(count);
- mCurrentReturnData->releaseFences.reserve(count);
- while (count > 0) {
- auto layer = read64();
- auto fence = readFence();
-
- mCurrentReturnData->releasedLayers.push_back(layer);
- mCurrentReturnData->releaseFences.push_back(fence);
-
- count--;
- }
-
- return true;
-}
-
-bool CommandReader::parseSetPresentOrValidateDisplayResult(uint16_t length)
-{
- if (length != CommandWriterBase::kPresentOrValidateDisplayResultLength || !mCurrentReturnData) {
- return false;
- }
- mCurrentReturnData->presentOrValidateState = read();
- return true;
-}
-
-bool CommandReader::parseSetClientTargetProperty(uint16_t length) {
- if (length != CommandWriterBase::kSetClientTargetPropertyLength || !mCurrentReturnData) {
- return false;
- }
- mCurrentReturnData->clientTargetProperty.pixelFormat = static_cast<PixelFormat>(readSigned());
- mCurrentReturnData->clientTargetProperty.dataspace = static_cast<Dataspace>(readSigned());
- return true;
-}
-
-void CommandReader::resetData()
-{
- mErrors.clear();
-
- for (auto& data : mReturnData) {
- if (data.second.presentFence >= 0) {
- close(data.second.presentFence);
- }
- for (auto fence : data.second.releaseFences) {
- if (fence >= 0) {
- close(fence);
- }
- }
- }
-
- mReturnData.clear();
- mCurrentReturnData = nullptr;
-}
-
-std::vector<CommandReader::CommandError> CommandReader::takeErrors()
-{
- return std::move(mErrors);
-}
-
-bool CommandReader::hasChanges(Display display,
- uint32_t* outNumChangedCompositionTypes,
- uint32_t* outNumLayerRequestMasks) const
-{
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- *outNumChangedCompositionTypes = 0;
- *outNumLayerRequestMasks = 0;
- return false;
- }
-
- const ReturnData& data = found->second;
-
- *outNumChangedCompositionTypes = data.compositionTypes.size();
- *outNumLayerRequestMasks = data.requestMasks.size();
-
- return !(data.compositionTypes.empty() && data.requestMasks.empty());
-}
-
-void CommandReader::takeChangedCompositionTypes(Display display,
- std::vector<Layer>* outLayers,
- std::vector<IComposerClient::Composition>* outTypes)
-{
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- outLayers->clear();
- outTypes->clear();
- return;
- }
-
- ReturnData& data = found->second;
-
- *outLayers = std::move(data.changedLayers);
- *outTypes = std::move(data.compositionTypes);
-}
-
-void CommandReader::takeDisplayRequests(Display display,
- uint32_t* outDisplayRequestMask, std::vector<Layer>* outLayers,
- std::vector<uint32_t>* outLayerRequestMasks)
-{
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- *outDisplayRequestMask = 0;
- outLayers->clear();
- outLayerRequestMasks->clear();
- return;
- }
-
- ReturnData& data = found->second;
-
- *outDisplayRequestMask = data.displayRequests;
- *outLayers = std::move(data.requestedLayers);
- *outLayerRequestMasks = std::move(data.requestMasks);
-}
-
-void CommandReader::takeReleaseFences(Display display,
- std::vector<Layer>* outLayers, std::vector<int>* outReleaseFences)
-{
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- outLayers->clear();
- outReleaseFences->clear();
- return;
- }
-
- ReturnData& data = found->second;
-
- *outLayers = std::move(data.releasedLayers);
- *outReleaseFences = std::move(data.releaseFences);
-}
-
-void CommandReader::takePresentFence(Display display, int* outPresentFence)
-{
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- *outPresentFence = -1;
- return;
- }
-
- ReturnData& data = found->second;
-
- *outPresentFence = data.presentFence;
- data.presentFence = -1;
-}
-
-void CommandReader::takePresentOrValidateStage(Display display, uint32_t* state) {
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- *state= -1;
- return;
- }
- ReturnData& data = found->second;
- *state = data.presentOrValidateState;
-}
-
-void CommandReader::takeClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
- auto found = mReturnData.find(display);
-
- // If not found, return the default values.
- if (found == mReturnData.end()) {
- outClientTargetProperty->pixelFormat = PixelFormat::RGBA_8888;
- outClientTargetProperty->dataspace = Dataspace::UNKNOWN;
- return;
- }
-
- ReturnData& data = found->second;
- *outClientTargetProperty = data.clientTargetProperty;
-}
-
-} // namespace impl
-} // namespace Hwc2
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+} // namespace android::Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index fe114b9..3bbce7b 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -14,24 +14,15 @@
* limitations under the License.
*/
-#ifndef ANDROID_SF_COMPOSER_HAL_H
-#define ANDROID_SF_COMPOSER_HAL_H
+#pragma once
#include <memory>
-#include <optional>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
// 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 <android/hardware/graphics/common/1.1/types.h>
-#include <android/hardware/graphics/composer/2.4/IComposer.h>
-#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
#include <gui/BufferQueue.h>
#include <gui/HdrMetadata.h>
@@ -43,9 +34,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
-namespace android {
-
-namespace Hwc2 {
+namespace android::Hwc2 {
namespace types = hardware::graphics::common;
@@ -80,6 +69,8 @@
class Composer {
public:
+ static std::unique_ptr<Composer> create(const std::string& serviceName);
+
virtual ~Composer() = 0;
virtual std::vector<IComposer::Capability> getCapabilities() = 0;
@@ -233,279 +224,4 @@
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
};
-namespace impl {
-
-class CommandReader : public CommandReaderBase {
-public:
- ~CommandReader();
-
- // Parse and execute commands from the command queue. The commands are
- // actually return values from the server and will be saved in ReturnData.
- Error parse();
-
- // Get and clear saved errors.
- struct CommandError {
- uint32_t location;
- Error error;
- };
- std::vector<CommandError> takeErrors();
-
- bool hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
- uint32_t* outNumLayerRequestMasks) const;
-
- // Get and clear saved changed composition types.
- void takeChangedCompositionTypes(Display display,
- std::vector<Layer>* outLayers,
- std::vector<IComposerClient::Composition>* outTypes);
-
- // Get and clear saved display requests.
- void takeDisplayRequests(Display display,
- uint32_t* outDisplayRequestMask, std::vector<Layer>* outLayers,
- std::vector<uint32_t>* outLayerRequestMasks);
-
- // Get and clear saved release fences.
- void takeReleaseFences(Display display, std::vector<Layer>* outLayers,
- std::vector<int>* outReleaseFences);
-
- // Get and clear saved present fence.
- void takePresentFence(Display display, int* outPresentFence);
-
- // Get what stage succeeded during PresentOrValidate: Present or Validate
- void takePresentOrValidateStage(Display display, uint32_t * state);
-
- // Get the client target properties requested by hardware composer.
- void takeClientTargetProperty(Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty);
-
-private:
- void resetData();
-
- bool parseSelectDisplay(uint16_t length);
- bool parseSetError(uint16_t length);
- bool parseSetChangedCompositionTypes(uint16_t length);
- bool parseSetDisplayRequests(uint16_t length);
- bool parseSetPresentFence(uint16_t length);
- bool parseSetReleaseFences(uint16_t length);
- bool parseSetPresentOrValidateDisplayResult(uint16_t length);
- bool parseSetClientTargetProperty(uint16_t length);
-
- struct ReturnData {
- uint32_t displayRequests = 0;
-
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
-
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
-
- int presentFence = -1;
-
- std::vector<Layer> releasedLayers;
- std::vector<int> releaseFences;
-
- uint32_t presentOrValidateState;
-
- // Composer 2.4 implementation can return a client target property
- // structure to indicate the client target properties that hardware
- // composer requests. The composer client must change the client target
- // properties to match this request.
- IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
- Dataspace::UNKNOWN};
- };
-
- std::vector<CommandError> mErrors;
- std::unordered_map<Display, ReturnData> mReturnData;
-
- // When SELECT_DISPLAY is parsed, this is updated to point to the
- // display's return data in mReturnData. We use it to avoid repeated
- // map lookups.
- ReturnData* mCurrentReturnData;
-};
-
-// Composer is a wrapper to IComposer, a proxy to server-side composer.
-class Composer final : public Hwc2::Composer {
-public:
- explicit Composer(const std::string& serviceName);
- ~Composer() override;
-
- std::vector<IComposer::Capability> getCapabilities() override;
- std::string dumpDebugInfo() override;
-
- void registerCallback(const sp<IComposerCallback>& callback) override;
-
- // Reset all pending commands in the command buffer. Useful if you want to
- // skip a frame but have already queued some commands.
- void resetCommands() override;
-
- // Explicitly flush all pending commands in the command buffer.
- Error executeCommands() override;
-
- uint32_t getMaxVirtualDisplayCount() override;
- Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
- Display* outDisplay) override;
- Error destroyVirtualDisplay(Display display) override;
-
- Error acceptDisplayChanges(Display display) override;
-
- Error createLayer(Display display, Layer* outLayer) override;
- Error destroyLayer(Display display, Layer layer) override;
-
- Error getActiveConfig(Display display, Config* outConfig) override;
- Error getChangedCompositionTypes(Display display, std::vector<Layer>* outLayers,
- std::vector<IComposerClient::Composition>* outTypes) override;
- Error getColorModes(Display display, std::vector<ColorMode>* outModes) override;
- Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
- int32_t* outValue) override;
- Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs);
- Error getDisplayName(Display display, std::string* outName) override;
-
- Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outLayers,
- std::vector<uint32_t>* outLayerRequestMasks) override;
-
- Error getDozeSupport(Display display, bool* outSupport) override;
- Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
- float* outMaxAverageLuminance, float* outMinLuminance) override;
-
- Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
- std::vector<int>* outReleaseFences) override;
-
- Error presentDisplay(Display display, int* outPresentFence) override;
-
- Error setActiveConfig(Display display, Config config) override;
-
- /*
- * The composer caches client targets internally. When target is nullptr,
- * the composer uses slot to look up the client target from its cache.
- * When target is not nullptr, the cache is updated with the new target.
- */
- Error setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
- int acquireFence, Dataspace dataspace,
- const std::vector<IComposerClient::Rect>& damage) override;
- Error setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) override;
- Error setColorTransform(Display display, const float* matrix, ColorTransform hint) override;
- Error setOutputBuffer(Display display, const native_handle_t* buffer,
- int releaseFence) override;
- Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
- Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
-
- Error setClientTargetSlotCount(Display display) override;
-
- Error validateDisplay(Display display, uint32_t* outNumTypes,
- uint32_t* outNumRequests) override;
-
- Error presentOrValidateDisplay(Display display, uint32_t* outNumTypes, uint32_t* outNumRequests,
- int* outPresentFence, uint32_t* state) override;
-
- Error setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
- /* see setClientTarget for the purpose of slot */
- Error setLayerBuffer(Display display, Layer layer, uint32_t slot,
- const sp<GraphicBuffer>& buffer, int acquireFence) override;
- Error setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<IComposerClient::Rect>& damage) override;
- Error setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) override;
- Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) override;
- Error setLayerCompositionType(Display display, Layer layer,
- IComposerClient::Composition type) override;
- Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) override;
- Error setLayerDisplayFrame(Display display, Layer layer,
- const IComposerClient::Rect& frame) override;
- Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
- Error setLayerSidebandStream(Display display, Layer layer,
- const native_handle_t* stream) override;
- Error setLayerSourceCrop(Display display, Layer layer,
- const IComposerClient::FRect& crop) override;
- Error setLayerTransform(Display display, Layer layer, Transform transform) override;
- Error setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<IComposerClient::Rect>& visible) override;
- Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
-
- // Composer HAL 2.2
- Error setLayerPerFrameMetadata(
- Display display, Layer layer,
- const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) override;
- std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(
- Display display) override;
- Error getRenderIntents(Display display, ColorMode colorMode,
- std::vector<RenderIntent>* outRenderIntents) override;
- Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) override;
-
- // Composer HAL 2.3
- Error getDisplayIdentificationData(Display display, uint8_t* outPort,
- std::vector<uint8_t>* outData) override;
- Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override;
- Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
- Dataspace* outDataspace,
- uint8_t* outComponentMask) override;
- Error setDisplayContentSamplingEnabled(Display display, bool enabled, uint8_t componentMask,
- uint64_t maxFrames) override;
- Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
- DisplayedFrameStats* outStats) override;
- Error setLayerPerFrameMetadataBlobs(
- Display display, Layer layer,
- const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness) override;
-
- // Composer HAL 2.4
- bool isVsyncPeriodSwitchSupported() override { return mClient_2_4 != nullptr; }
- Error getDisplayCapabilities(Display display,
- std::vector<DisplayCapability>* outCapabilities) override;
- V2_4::Error getDisplayConnectionType(Display display,
- IComposerClient::DisplayConnectionType* outType) override;
- V2_4::Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override;
- V2_4::Error setActiveConfigWithConstraints(
- Display display, Config config,
- const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
- VsyncPeriodChangeTimeline* outTimeline) override;
- V2_4::Error setAutoLowLatencyMode(Display displayId, bool on) override;
- V2_4::Error getSupportedContentTypes(
- Display displayId,
- std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
- V2_4::Error setContentType(Display displayId,
- IComposerClient::ContentType contentType) override;
- V2_4::Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
- 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) override;
-
-private:
- class CommandWriter : public CommandWriterBase {
- public:
- explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {}
- ~CommandWriter() override {}
- };
-
- // Many public functions above simply write a command into the command
- // queue to batch the calls. validateDisplay and presentDisplay will call
- // this function to execute the command queue.
- Error execute();
-
- sp<V2_1::IComposer> mComposer;
-
- sp<V2_1::IComposerClient> mClient;
- sp<V2_2::IComposerClient> mClient_2_2;
- sp<V2_3::IComposerClient> mClient_2_3;
- sp<IComposerClient> mClient_2_4;
-
- // 64KiB minus a small space for metadata such as read/write pointers
- static constexpr size_t kWriterInitialSize =
- 64 * 1024 / sizeof(uint32_t) - 16;
- // Max number of buffers that may be cached for a given layer
- // We obtain this number by:
- // 1. Tightly coupling this cache to the max size of BufferQueue
- // 2. Adding an additional slot for the layer caching feature in SurfaceFlinger (see: Planner.h)
- static const constexpr uint32_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
- CommandWriter mWriter;
- CommandReader mReader;
-};
-
-} // namespace impl
-
-} // namespace Hwc2
-
-} // namespace android
-
-#endif // ANDROID_SF_COMPOSER_HAL_H
+} // namespace android::Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c63ba0e..06f5df5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -143,7 +143,7 @@
sysprop::update_device_product_info_on_hotplug_reconnect(false)) {}
HWComposer::HWComposer(const std::string& composerServiceName)
- : HWComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {}
+ : HWComposer(Hwc2::Composer::create(composerServiceName)) {}
HWComposer::~HWComposer() {
mDisplayData.clear();
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
new file mode 100644
index 0000000..6c40598
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -0,0 +1,1480 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "HwcComposer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "HidlComposerHal.h"
+
+#include <android/binder_manager.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/HidlTransportUtils.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <algorithm>
+#include <cinttypes>
+
+namespace android {
+
+using hardware::hidl_handle;
+using hardware::hidl_vec;
+using hardware::Return;
+
+namespace Hwc2 {
+
+HidlComposer::~HidlComposer() = default;
+
+namespace {
+
+class BufferHandle {
+public:
+ explicit BufferHandle(const native_handle_t* buffer) {
+ // nullptr is not a valid handle to HIDL
+ mHandle = (buffer) ? buffer : native_handle_init(mStorage, 0, 0);
+ }
+
+ operator const hidl_handle&() const // NOLINT(google-explicit-constructor)
+ {
+ return mHandle;
+ }
+
+private:
+ NATIVE_HANDLE_DECLARE_STORAGE(mStorage, 0, 0);
+ hidl_handle mHandle;
+};
+
+class FenceHandle {
+public:
+ FenceHandle(int fd, bool owned) : mOwned(owned) {
+ native_handle_t* handle;
+ if (fd >= 0) {
+ handle = native_handle_init(mStorage, 1, 0);
+ handle->data[0] = fd;
+ } else {
+ // nullptr is not a valid handle to HIDL
+ handle = native_handle_init(mStorage, 0, 0);
+ }
+ mHandle = handle;
+ }
+
+ ~FenceHandle() {
+ if (mOwned) {
+ native_handle_close(mHandle);
+ }
+ }
+
+ operator const hidl_handle&() const // NOLINT(google-explicit-constructor)
+ {
+ return mHandle;
+ }
+
+private:
+ bool mOwned;
+ NATIVE_HANDLE_DECLARE_STORAGE(mStorage, 1, 0);
+ hidl_handle mHandle;
+};
+
+// assume NO_RESOURCES when Status::isOk returns false
+constexpr Error kDefaultError = Error::NO_RESOURCES;
+constexpr V2_4::Error kDefaultError_2_4 = static_cast<V2_4::Error>(kDefaultError);
+
+template <typename T, typename U>
+T unwrapRet(Return<T>& ret, const U& default_val) {
+ return (ret.isOk()) ? static_cast<T>(ret) : static_cast<T>(default_val);
+}
+
+Error unwrapRet(Return<Error>& ret) {
+ return unwrapRet(ret, kDefaultError);
+}
+
+} // anonymous namespace
+
+HidlComposer::HidlComposer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
+ mComposer = V2_1::IComposer::getService(serviceName);
+
+ if (mComposer == nullptr) {
+ LOG_ALWAYS_FATAL("failed to get hwcomposer service");
+ }
+
+ if (sp<IComposer> composer_2_4 = IComposer::castFrom(mComposer)) {
+ composer_2_4->createClient_2_4([&](const auto& tmpError, const auto& tmpClient) {
+ if (tmpError == V2_4::Error::NONE) {
+ mClient = tmpClient;
+ mClient_2_2 = tmpClient;
+ mClient_2_3 = tmpClient;
+ mClient_2_4 = tmpClient;
+ }
+ });
+ } else if (sp<V2_3::IComposer> composer_2_3 = V2_3::IComposer::castFrom(mComposer)) {
+ composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) {
+ if (tmpError == Error::NONE) {
+ mClient = tmpClient;
+ mClient_2_2 = tmpClient;
+ mClient_2_3 = tmpClient;
+ }
+ });
+ } else {
+ mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ mClient = tmpClient;
+ if (sp<V2_2::IComposer> composer_2_2 = V2_2::IComposer::castFrom(mComposer)) {
+ mClient_2_2 = V2_2::IComposerClient::castFrom(mClient);
+ LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr,
+ "IComposer 2.2 did not return IComposerClient 2.2");
+ }
+ });
+ }
+
+ if (mClient == nullptr) {
+ LOG_ALWAYS_FATAL("failed to create composer client");
+ }
+}
+
+std::vector<IComposer::Capability> HidlComposer::getCapabilities() {
+ std::vector<IComposer::Capability> capabilities;
+ mComposer->getCapabilities(
+ [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
+ return capabilities;
+}
+
+std::string HidlComposer::dumpDebugInfo() {
+ std::string info;
+ mComposer->dumpDebugInfo([&](const auto& tmpInfo) { info = tmpInfo.c_str(); });
+
+ return info;
+}
+
+void HidlComposer::registerCallback(const sp<IComposerCallback>& callback) {
+ android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
+
+ auto ret = [&]() {
+ if (mClient_2_4) {
+ return mClient_2_4->registerCallback_2_4(callback);
+ }
+ return mClient->registerCallback(callback);
+ }();
+ if (!ret.isOk()) {
+ ALOGE("failed to register IComposerCallback");
+ }
+}
+
+void HidlComposer::resetCommands() {
+ mWriter.reset();
+}
+
+Error HidlComposer::executeCommands() {
+ return execute();
+}
+
+uint32_t HidlComposer::getMaxVirtualDisplayCount() {
+ auto ret = mClient->getMaxVirtualDisplayCount();
+ return unwrapRet(ret, 0);
+}
+
+Error HidlComposer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+ Display* outDisplay) {
+ const uint32_t bufferSlotCount = 1;
+ Error error = kDefaultError;
+ if (mClient_2_2) {
+ mClient_2_2->createVirtualDisplay_2_2(width, height,
+ static_cast<types::V1_1::PixelFormat>(*format),
+ bufferSlotCount,
+ [&](const auto& tmpError, const auto& tmpDisplay,
+ const auto& tmpFormat) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outDisplay = tmpDisplay;
+ *format = static_cast<types::V1_2::PixelFormat>(
+ tmpFormat);
+ });
+ } else {
+ mClient->createVirtualDisplay(width, height, static_cast<types::V1_0::PixelFormat>(*format),
+ bufferSlotCount,
+ [&](const auto& tmpError, const auto& tmpDisplay,
+ const auto& tmpFormat) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outDisplay = tmpDisplay;
+ *format = static_cast<PixelFormat>(tmpFormat);
+ });
+ }
+
+ return error;
+}
+
+Error HidlComposer::destroyVirtualDisplay(Display display) {
+ auto ret = mClient->destroyVirtualDisplay(display);
+ return unwrapRet(ret);
+}
+
+Error HidlComposer::acceptDisplayChanges(Display display) {
+ mWriter.selectDisplay(display);
+ mWriter.acceptDisplayChanges();
+ return Error::NONE;
+}
+
+Error HidlComposer::createLayer(Display display, Layer* outLayer) {
+ Error error = kDefaultError;
+ mClient->createLayer(display, kMaxLayerBufferCount,
+ [&](const auto& tmpError, const auto& tmpLayer) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outLayer = tmpLayer;
+ });
+
+ return error;
+}
+
+Error HidlComposer::destroyLayer(Display display, Layer layer) {
+ auto ret = mClient->destroyLayer(display, layer);
+ return unwrapRet(ret);
+}
+
+Error HidlComposer::getActiveConfig(Display display, Config* outConfig) {
+ Error error = kDefaultError;
+ mClient->getActiveConfig(display, [&](const auto& tmpError, const auto& tmpConfig) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outConfig = tmpConfig;
+ });
+
+ return error;
+}
+
+Error HidlComposer::getChangedCompositionTypes(
+ Display display, std::vector<Layer>* outLayers,
+ std::vector<IComposerClient::Composition>* outTypes) {
+ mReader.takeChangedCompositionTypes(display, outLayers, outTypes);
+ return Error::NONE;
+}
+
+Error HidlComposer::getColorModes(Display display, std::vector<ColorMode>* outModes) {
+ Error error = kDefaultError;
+
+ if (mClient_2_3) {
+ mClient_2_3->getColorModes_2_3(display, [&](const auto& tmpError, const auto& tmpModes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outModes = tmpModes;
+ });
+ } else if (mClient_2_2) {
+ mClient_2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ for (types::V1_1::ColorMode colorMode : tmpModes) {
+ outModes->push_back(static_cast<ColorMode>(colorMode));
+ }
+ });
+ } else {
+ mClient->getColorModes(display, [&](const auto& tmpError, const auto& tmpModes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ for (types::V1_0::ColorMode colorMode : tmpModes) {
+ outModes->push_back(static_cast<ColorMode>(colorMode));
+ }
+ });
+ }
+
+ return error;
+}
+
+Error HidlComposer::getDisplayAttribute(Display display, Config config,
+ IComposerClient::Attribute attribute, int32_t* outValue) {
+ Error error = kDefaultError;
+ if (mClient_2_4) {
+ mClient_2_4->getDisplayAttribute_2_4(display, config, attribute,
+ [&](const auto& tmpError, const auto& tmpValue) {
+ error = static_cast<Error>(tmpError);
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outValue = tmpValue;
+ });
+ } else {
+ mClient->getDisplayAttribute(display, config,
+ static_cast<V2_1::IComposerClient::Attribute>(attribute),
+ [&](const auto& tmpError, const auto& tmpValue) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outValue = tmpValue;
+ });
+ }
+
+ return error;
+}
+
+Error HidlComposer::getDisplayConfigs(Display display, std::vector<Config>* outConfigs) {
+ Error error = kDefaultError;
+ mClient->getDisplayConfigs(display, [&](const auto& tmpError, const auto& tmpConfigs) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outConfigs = tmpConfigs;
+ });
+
+ return error;
+}
+
+Error HidlComposer::getDisplayName(Display display, std::string* outName) {
+ Error error = kDefaultError;
+ mClient->getDisplayName(display, [&](const auto& tmpError, const auto& tmpName) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outName = tmpName.c_str();
+ });
+
+ return error;
+}
+
+Error HidlComposer::getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outLayers,
+ std::vector<uint32_t>* outLayerRequestMasks) {
+ mReader.takeDisplayRequests(display, outDisplayRequestMask, outLayers, outLayerRequestMasks);
+ return Error::NONE;
+}
+
+Error HidlComposer::getDozeSupport(Display display, bool* outSupport) {
+ Error error = kDefaultError;
+ mClient->getDozeSupport(display, [&](const auto& tmpError, const auto& tmpSupport) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outSupport = tmpSupport;
+ });
+
+ return error;
+}
+
+Error HidlComposer::getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
+ float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance) {
+ Error error = kDefaultError;
+ if (mClient_2_3) {
+ mClient_2_3->getHdrCapabilities_2_3(display,
+ [&](const auto& tmpError, const auto& tmpTypes,
+ const auto& tmpMaxLuminance,
+ const auto& tmpMaxAverageLuminance,
+ const auto& tmpMinLuminance) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outTypes = tmpTypes;
+ *outMaxLuminance = tmpMaxLuminance;
+ *outMaxAverageLuminance = tmpMaxAverageLuminance;
+ *outMinLuminance = tmpMinLuminance;
+ });
+ } else {
+ mClient->getHdrCapabilities(display,
+ [&](const auto& tmpError, const auto& tmpTypes,
+ const auto& tmpMaxLuminance,
+ const auto& tmpMaxAverageLuminance,
+ const auto& tmpMinLuminance) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ outTypes->clear();
+ for (auto type : tmpTypes) {
+ outTypes->push_back(static_cast<Hdr>(type));
+ }
+
+ *outMaxLuminance = tmpMaxLuminance;
+ *outMaxAverageLuminance = tmpMaxAverageLuminance;
+ *outMinLuminance = tmpMinLuminance;
+ });
+ }
+
+ return error;
+}
+
+Error HidlComposer::getReleaseFences(Display display, std::vector<Layer>* outLayers,
+ std::vector<int>* outReleaseFences) {
+ mReader.takeReleaseFences(display, outLayers, outReleaseFences);
+ return Error::NONE;
+}
+
+Error HidlComposer::presentDisplay(Display display, int* outPresentFence) {
+ ATRACE_NAME("HwcPresentDisplay");
+ mWriter.selectDisplay(display);
+ mWriter.presentDisplay();
+
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ mReader.takePresentFence(display, outPresentFence);
+
+ return Error::NONE;
+}
+
+Error HidlComposer::setActiveConfig(Display display, Config config) {
+ auto ret = mClient->setActiveConfig(display, config);
+ return unwrapRet(ret);
+}
+
+Error HidlComposer::setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
+ int acquireFence, Dataspace dataspace,
+ const std::vector<IComposerClient::Rect>& damage) {
+ mWriter.selectDisplay(display);
+
+ const native_handle_t* handle = nullptr;
+ if (target.get()) {
+ handle = target->getNativeBuffer()->handle;
+ }
+
+ mWriter.setClientTarget(slot, handle, acquireFence, dataspace, damage);
+ return Error::NONE;
+}
+
+Error HidlComposer::setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) {
+ hardware::Return<Error> ret(kDefaultError);
+ if (mClient_2_3) {
+ ret = mClient_2_3->setColorMode_2_3(display, mode, renderIntent);
+ } else if (mClient_2_2) {
+ ret = mClient_2_2->setColorMode_2_2(display, static_cast<types::V1_1::ColorMode>(mode),
+ renderIntent);
+ } else {
+ ret = mClient->setColorMode(display, static_cast<types::V1_0::ColorMode>(mode));
+ }
+ return unwrapRet(ret);
+}
+
+Error HidlComposer::setColorTransform(Display display, const float* matrix, ColorTransform hint) {
+ mWriter.selectDisplay(display);
+ mWriter.setColorTransform(matrix, hint);
+ return Error::NONE;
+}
+
+Error HidlComposer::setOutputBuffer(Display display, const native_handle_t* buffer,
+ int releaseFence) {
+ mWriter.selectDisplay(display);
+ mWriter.setOutputBuffer(0, buffer, dup(releaseFence));
+ return Error::NONE;
+}
+
+Error HidlComposer::setPowerMode(Display display, IComposerClient::PowerMode mode) {
+ Return<Error> ret(Error::UNSUPPORTED);
+ if (mClient_2_2) {
+ ret = mClient_2_2->setPowerMode_2_2(display, mode);
+ } else if (mode != IComposerClient::PowerMode::ON_SUSPEND) {
+ ret = mClient->setPowerMode(display, static_cast<V2_1::IComposerClient::PowerMode>(mode));
+ }
+
+ return unwrapRet(ret);
+}
+
+Error HidlComposer::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
+ auto ret = mClient->setVsyncEnabled(display, enabled);
+ return unwrapRet(ret);
+}
+
+Error HidlComposer::setClientTargetSlotCount(Display display) {
+ const uint32_t bufferSlotCount = BufferQueue::NUM_BUFFER_SLOTS;
+ auto ret = mClient->setClientTargetSlotCount(display, bufferSlotCount);
+ return unwrapRet(ret);
+}
+
+Error HidlComposer::validateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests) {
+ ATRACE_NAME("HwcValidateDisplay");
+ mWriter.selectDisplay(display);
+ mWriter.validateDisplay();
+
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ mReader.hasChanges(display, outNumTypes, outNumRequests);
+
+ return Error::NONE;
+}
+
+Error HidlComposer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests, int* outPresentFence,
+ uint32_t* state) {
+ ATRACE_NAME("HwcPresentOrValidateDisplay");
+ mWriter.selectDisplay(display);
+ mWriter.presentOrvalidateDisplay();
+
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ mReader.takePresentOrValidateStage(display, state);
+
+ if (*state == 1) { // Present succeeded
+ mReader.takePresentFence(display, outPresentFence);
+ }
+
+ if (*state == 0) { // Validate succeeded.
+ mReader.hasChanges(display, outNumTypes, outNumRequests);
+ }
+
+ return Error::NONE;
+}
+
+Error HidlComposer::setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerCursorPosition(x, y);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerBuffer(Display display, Layer layer, uint32_t slot,
+ const sp<GraphicBuffer>& buffer, int acquireFence) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+
+ const native_handle_t* handle = nullptr;
+ if (buffer.get()) {
+ handle = buffer->getNativeBuffer()->handle;
+ }
+
+ mWriter.setLayerBuffer(slot, handle, acquireFence);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& damage) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerSurfaceDamage(damage);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerBlendMode(Display display, Layer layer,
+ IComposerClient::BlendMode mode) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerBlendMode(mode);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerColor(Display display, Layer layer,
+ const IComposerClient::Color& color) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerColor(color);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerCompositionType(Display display, Layer layer,
+ IComposerClient::Composition type) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerCompositionType(type);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerDataspace(Display display, Layer layer, Dataspace dataspace) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerDataspace(dataspace);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerDisplayFrame(Display display, Layer layer,
+ const IComposerClient::Rect& frame) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerDisplayFrame(frame);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerPlaneAlpha(alpha);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerSidebandStream(Display display, Layer layer,
+ const native_handle_t* stream) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerSidebandStream(stream);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerSourceCrop(Display display, Layer layer,
+ const IComposerClient::FRect& crop) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerSourceCrop(crop);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerTransform(Display display, Layer layer, Transform transform) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerTransform(transform);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& visible) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerVisibleRegion(visible);
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerZOrder(Display display, Layer layer, uint32_t z) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerZOrder(z);
+ return Error::NONE;
+}
+
+Error HidlComposer::execute() {
+ // prepare input command queue
+ bool queueChanged = false;
+ uint32_t commandLength = 0;
+ hidl_vec<hidl_handle> commandHandles;
+ if (!mWriter.writeQueue(&queueChanged, &commandLength, &commandHandles)) {
+ mWriter.reset();
+ return Error::NO_RESOURCES;
+ }
+
+ // set up new input command queue if necessary
+ if (queueChanged) {
+ auto ret = mClient->setInputCommandQueue(*mWriter.getMQDescriptor());
+ auto error = unwrapRet(ret);
+ if (error != Error::NONE) {
+ mWriter.reset();
+ return error;
+ }
+ }
+
+ if (commandLength == 0) {
+ mWriter.reset();
+ return Error::NONE;
+ }
+
+ Error error = kDefaultError;
+ hardware::Return<void> ret;
+ auto hidl_callback = [&](const auto& tmpError, const auto& tmpOutChanged,
+ const auto& tmpOutLength, const auto& tmpOutHandles) {
+ error = tmpError;
+
+ // set up new output command queue if necessary
+ if (error == Error::NONE && tmpOutChanged) {
+ error = kDefaultError;
+ mClient->getOutputCommandQueue([&](const auto& tmpError, const auto& tmpDescriptor) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ mReader.setMQDescriptor(tmpDescriptor);
+ });
+ }
+
+ if (error != Error::NONE) {
+ return;
+ }
+
+ if (mReader.readQueue(tmpOutLength, tmpOutHandles)) {
+ error = mReader.parse();
+ mReader.reset();
+ } else {
+ error = Error::NO_RESOURCES;
+ }
+ };
+ if (mClient_2_2) {
+ ret = mClient_2_2->executeCommands_2_2(commandLength, commandHandles, hidl_callback);
+ } else {
+ ret = mClient->executeCommands(commandLength, commandHandles, hidl_callback);
+ }
+ // executeCommands can fail because of out-of-fd and we do not want to
+ // abort() in that case
+ if (!ret.isOk()) {
+ ALOGE("executeCommands failed because of %s", ret.description().c_str());
+ }
+
+ if (error == Error::NONE) {
+ std::vector<CommandReader::CommandError> commandErrors = mReader.takeErrors();
+
+ for (const auto& cmdErr : commandErrors) {
+ auto command =
+ static_cast<IComposerClient::Command>(mWriter.getCommand(cmdErr.location));
+
+ if (command == IComposerClient::Command::VALIDATE_DISPLAY ||
+ command == IComposerClient::Command::PRESENT_DISPLAY ||
+ command == IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY) {
+ error = cmdErr.error;
+ } else {
+ ALOGW("command 0x%x generated error %d", command, cmdErr.error);
+ }
+ }
+ }
+
+ mWriter.reset();
+
+ return error;
+}
+
+// Composer HAL 2.2
+
+Error HidlComposer::setLayerPerFrameMetadata(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) {
+ if (!mClient_2_2) {
+ return Error::UNSUPPORTED;
+ }
+
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerPerFrameMetadata(perFrameMetadatas);
+ return Error::NONE;
+}
+
+std::vector<IComposerClient::PerFrameMetadataKey> HidlComposer::getPerFrameMetadataKeys(
+ Display display) {
+ std::vector<IComposerClient::PerFrameMetadataKey> keys;
+ if (!mClient_2_2) {
+ return keys;
+ }
+
+ Error error = kDefaultError;
+ if (mClient_2_3) {
+ mClient_2_3->getPerFrameMetadataKeys_2_3(display,
+ [&](const auto& tmpError, const auto& tmpKeys) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ ALOGW("getPerFrameMetadataKeys failed "
+ "with %d",
+ tmpError);
+ return;
+ }
+ keys = tmpKeys;
+ });
+ } else {
+ mClient_2_2
+ ->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ ALOGW("getPerFrameMetadataKeys failed with %d", tmpError);
+ return;
+ }
+
+ keys.clear();
+ for (auto key : tmpKeys) {
+ keys.push_back(static_cast<IComposerClient::PerFrameMetadataKey>(key));
+ }
+ });
+ }
+
+ return keys;
+}
+
+Error HidlComposer::getRenderIntents(Display display, ColorMode colorMode,
+ std::vector<RenderIntent>* outRenderIntents) {
+ if (!mClient_2_2) {
+ outRenderIntents->push_back(RenderIntent::COLORIMETRIC);
+ return Error::NONE;
+ }
+
+ Error error = kDefaultError;
+
+ auto getRenderIntentsLambda = [&](const auto& tmpError, const auto& tmpKeys) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outRenderIntents = tmpKeys;
+ };
+
+ if (mClient_2_3) {
+ mClient_2_3->getRenderIntents_2_3(display, colorMode, getRenderIntentsLambda);
+ } else {
+ mClient_2_2->getRenderIntents(display, static_cast<types::V1_1::ColorMode>(colorMode),
+ getRenderIntentsLambda);
+ }
+
+ return error;
+}
+
+Error HidlComposer::getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) {
+ if (!mClient_2_2) {
+ *outMatrix = mat4();
+ return Error::NONE;
+ }
+
+ Error error = kDefaultError;
+ mClient_2_2->getDataspaceSaturationMatrix(static_cast<types::V1_1::Dataspace>(dataspace),
+ [&](const auto& tmpError, const auto& tmpMatrix) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outMatrix = mat4(tmpMatrix.data());
+ });
+
+ return error;
+}
+
+// Composer HAL 2.3
+
+Error HidlComposer::getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) {
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+
+ Error error = kDefaultError;
+ mClient_2_3->getDisplayIdentificationData(display,
+ [&](const auto& tmpError, const auto& tmpPort,
+ const auto& tmpData) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outPort = tmpPort;
+ *outData = tmpData;
+ });
+
+ return error;
+}
+
+Error HidlComposer::setLayerColorTransform(Display display, Layer layer, const float* matrix) {
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerColorTransform(matrix);
+ return Error::NONE;
+}
+
+Error HidlComposer::getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace,
+ uint8_t* outComponentMask) {
+ if (!outFormat || !outDataspace || !outComponentMask) {
+ return Error::BAD_PARAMETER;
+ }
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+ Error error = kDefaultError;
+ mClient_2_3->getDisplayedContentSamplingAttributes(display,
+ [&](const auto tmpError,
+ const auto& tmpFormat,
+ const auto& tmpDataspace,
+ const auto& tmpComponentMask) {
+ error = tmpError;
+ if (error == Error::NONE) {
+ *outFormat = tmpFormat;
+ *outDataspace = tmpDataspace;
+ *outComponentMask =
+ static_cast<uint8_t>(
+ tmpComponentMask);
+ }
+ });
+ return error;
+}
+
+Error HidlComposer::setDisplayContentSamplingEnabled(Display display, bool enabled,
+ uint8_t componentMask, uint64_t maxFrames) {
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+
+ auto enable = enabled ? V2_3::IComposerClient::DisplayedContentSampling::ENABLE
+ : V2_3::IComposerClient::DisplayedContentSampling::DISABLE;
+ return mClient_2_3->setDisplayedContentSamplingEnabled(display, enable, componentMask,
+ maxFrames);
+}
+
+Error HidlComposer::getDisplayedContentSample(Display display, uint64_t maxFrames,
+ uint64_t timestamp, DisplayedFrameStats* outStats) {
+ if (!outStats) {
+ return Error::BAD_PARAMETER;
+ }
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+ Error error = kDefaultError;
+ mClient_2_3->getDisplayedContentSample(display, maxFrames, timestamp,
+ [&](const auto tmpError, auto tmpNumFrames,
+ const auto& tmpSamples0, const auto& tmpSamples1,
+ const auto& tmpSamples2, const auto& tmpSamples3) {
+ error = tmpError;
+ if (error == Error::NONE) {
+ outStats->numFrames = tmpNumFrames;
+ outStats->component_0_sample = tmpSamples0;
+ outStats->component_1_sample = tmpSamples1;
+ outStats->component_2_sample = tmpSamples2;
+ outStats->component_3_sample = tmpSamples3;
+ }
+ });
+ return error;
+}
+
+Error HidlComposer::setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) {
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerPerFrameMetadataBlobs(metadata);
+ return Error::NONE;
+}
+
+Error HidlComposer::setDisplayBrightness(Display display, float brightness) {
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+ return mClient_2_3->setDisplayBrightness(display, brightness);
+}
+
+// Composer HAL 2.4
+
+Error HidlComposer::getDisplayCapabilities(Display display,
+ std::vector<DisplayCapability>* outCapabilities) {
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+
+ V2_4::Error error = kDefaultError_2_4;
+ if (mClient_2_4) {
+ mClient_2_4->getDisplayCapabilities_2_4(display,
+ [&](const auto& tmpError, const auto& tmpCaps) {
+ error = tmpError;
+ if (error != V2_4::Error::NONE) {
+ return;
+ }
+ *outCapabilities = tmpCaps;
+ });
+ } else {
+ mClient_2_3
+ ->getDisplayCapabilities(display, [&](const auto& tmpError, const auto& tmpCaps) {
+ error = static_cast<V2_4::Error>(tmpError);
+ if (error != V2_4::Error::NONE) {
+ return;
+ }
+
+ outCapabilities->resize(tmpCaps.size());
+ std::transform(tmpCaps.begin(), tmpCaps.end(), outCapabilities->begin(),
+ [](auto cap) { return static_cast<DisplayCapability>(cap); });
+ });
+ }
+
+ return static_cast<Error>(error);
+}
+
+V2_4::Error HidlComposer::getDisplayConnectionType(
+ Display display, IComposerClient::DisplayConnectionType* outType) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ Error error = kDefaultError_2_4;
+ mClient_2_4->getDisplayConnectionType(display, [&](const auto& tmpError, const auto& tmpType) {
+ error = tmpError;
+ if (error != V2_4::Error::NONE) {
+ return;
+ }
+
+ *outType = tmpType;
+ });
+
+ return error;
+}
+
+V2_4::Error HidlComposer::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ Error error = kDefaultError_2_4;
+ mClient_2_4->getDisplayVsyncPeriod(display,
+ [&](const auto& tmpError, const auto& tmpVsyncPeriod) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outVsyncPeriod = tmpVsyncPeriod;
+ });
+
+ return error;
+}
+
+V2_4::Error HidlComposer::setActiveConfigWithConstraints(
+ Display display, Config config,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ VsyncPeriodChangeTimeline* outTimeline) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ Error error = kDefaultError_2_4;
+ mClient_2_4->setActiveConfigWithConstraints(display, config, vsyncPeriodChangeConstraints,
+ [&](const auto& tmpError, const auto& tmpTimeline) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outTimeline = tmpTimeline;
+ });
+
+ return error;
+}
+
+V2_4::Error HidlComposer::setAutoLowLatencyMode(Display display, bool on) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ return mClient_2_4->setAutoLowLatencyMode(display, on);
+}
+
+V2_4::Error HidlComposer::getSupportedContentTypes(
+ Display displayId, std::vector<IComposerClient::ContentType>* outSupportedContentTypes) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ Error error = kDefaultError_2_4;
+ mClient_2_4->getSupportedContentTypes(displayId,
+ [&](const auto& tmpError,
+ const auto& tmpSupportedContentTypes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outSupportedContentTypes = tmpSupportedContentTypes;
+ });
+ return error;
+}
+
+V2_4::Error HidlComposer::setContentType(Display display,
+ IComposerClient::ContentType contentType) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+
+ return mClient_2_4->setContentType(display, contentType);
+}
+
+V2_4::Error HidlComposer::setLayerGenericMetadata(Display display, Layer layer,
+ const std::string& key, bool mandatory,
+ const std::vector<uint8_t>& value) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ mWriter.setLayerGenericMetadata(key, mandatory, value);
+ return Error::NONE;
+}
+
+V2_4::Error HidlComposer::getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
+ using Error = V2_4::Error;
+ if (!mClient_2_4) {
+ return Error::UNSUPPORTED;
+ }
+ Error error = kDefaultError_2_4;
+ mClient_2_4->getLayerGenericMetadataKeys([&](const auto& tmpError, const auto& tmpKeys) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outKeys = tmpKeys;
+ });
+ return error;
+}
+
+Error HidlComposer::getClientTargetProperty(
+ Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
+ mReader.takeClientTargetProperty(display, outClientTargetProperty);
+ return Error::NONE;
+}
+
+CommandReader::~CommandReader() {
+ resetData();
+}
+
+Error CommandReader::parse() {
+ resetData();
+
+ IComposerClient::Command command;
+ uint16_t length = 0;
+
+ while (!isEmpty()) {
+ if (!beginCommand(&command, &length)) {
+ break;
+ }
+
+ bool parsed = false;
+ switch (command) {
+ case IComposerClient::Command::SELECT_DISPLAY:
+ parsed = parseSelectDisplay(length);
+ break;
+ case IComposerClient::Command::SET_ERROR:
+ parsed = parseSetError(length);
+ break;
+ case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
+ parsed = parseSetChangedCompositionTypes(length);
+ break;
+ case IComposerClient::Command::SET_DISPLAY_REQUESTS:
+ parsed = parseSetDisplayRequests(length);
+ break;
+ case IComposerClient::Command::SET_PRESENT_FENCE:
+ parsed = parseSetPresentFence(length);
+ break;
+ case IComposerClient::Command::SET_RELEASE_FENCES:
+ parsed = parseSetReleaseFences(length);
+ break;
+ case IComposerClient::Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
+ parsed = parseSetPresentOrValidateDisplayResult(length);
+ break;
+ case IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY:
+ parsed = parseSetClientTargetProperty(length);
+ break;
+ default:
+ parsed = false;
+ break;
+ }
+
+ endCommand();
+
+ if (!parsed) {
+ ALOGE("failed to parse command 0x%x length %" PRIu16, command, length);
+ break;
+ }
+ }
+
+ return isEmpty() ? Error::NONE : Error::NO_RESOURCES;
+}
+
+bool CommandReader::parseSelectDisplay(uint16_t length) {
+ if (length != CommandWriterBase::kSelectDisplayLength) {
+ return false;
+ }
+
+ mCurrentReturnData = &mReturnData[read64()];
+
+ return true;
+}
+
+bool CommandReader::parseSetError(uint16_t length) {
+ if (length != CommandWriterBase::kSetErrorLength) {
+ return false;
+ }
+
+ auto location = read();
+ auto error = static_cast<Error>(readSigned());
+
+ mErrors.emplace_back(CommandError{location, error});
+
+ return true;
+}
+
+bool CommandReader::parseSetChangedCompositionTypes(uint16_t length) {
+ // (layer id, composition type) pairs
+ if (length % 3 != 0 || !mCurrentReturnData) {
+ return false;
+ }
+
+ uint32_t count = length / 3;
+ mCurrentReturnData->changedLayers.reserve(count);
+ mCurrentReturnData->compositionTypes.reserve(count);
+ while (count > 0) {
+ auto layer = read64();
+ auto type = static_cast<IComposerClient::Composition>(readSigned());
+
+ mCurrentReturnData->changedLayers.push_back(layer);
+ mCurrentReturnData->compositionTypes.push_back(type);
+
+ count--;
+ }
+
+ return true;
+}
+
+bool CommandReader::parseSetDisplayRequests(uint16_t length) {
+ // display requests followed by (layer id, layer requests) pairs
+ if (length % 3 != 1 || !mCurrentReturnData) {
+ return false;
+ }
+
+ mCurrentReturnData->displayRequests = read();
+
+ uint32_t count = (length - 1) / 3;
+ mCurrentReturnData->requestedLayers.reserve(count);
+ mCurrentReturnData->requestMasks.reserve(count);
+ while (count > 0) {
+ auto layer = read64();
+ auto layerRequestMask = read();
+
+ mCurrentReturnData->requestedLayers.push_back(layer);
+ mCurrentReturnData->requestMasks.push_back(layerRequestMask);
+
+ count--;
+ }
+
+ return true;
+}
+
+bool CommandReader::parseSetPresentFence(uint16_t length) {
+ if (length != CommandWriterBase::kSetPresentFenceLength || !mCurrentReturnData) {
+ return false;
+ }
+
+ if (mCurrentReturnData->presentFence >= 0) {
+ close(mCurrentReturnData->presentFence);
+ }
+ mCurrentReturnData->presentFence = readFence();
+
+ return true;
+}
+
+bool CommandReader::parseSetReleaseFences(uint16_t length) {
+ // (layer id, release fence index) pairs
+ if (length % 3 != 0 || !mCurrentReturnData) {
+ return false;
+ }
+
+ uint32_t count = length / 3;
+ mCurrentReturnData->releasedLayers.reserve(count);
+ mCurrentReturnData->releaseFences.reserve(count);
+ while (count > 0) {
+ auto layer = read64();
+ auto fence = readFence();
+
+ mCurrentReturnData->releasedLayers.push_back(layer);
+ mCurrentReturnData->releaseFences.push_back(fence);
+
+ count--;
+ }
+
+ return true;
+}
+
+bool CommandReader::parseSetPresentOrValidateDisplayResult(uint16_t length) {
+ if (length != CommandWriterBase::kPresentOrValidateDisplayResultLength || !mCurrentReturnData) {
+ return false;
+ }
+ mCurrentReturnData->presentOrValidateState = read();
+ return true;
+}
+
+bool CommandReader::parseSetClientTargetProperty(uint16_t length) {
+ if (length != CommandWriterBase::kSetClientTargetPropertyLength || !mCurrentReturnData) {
+ return false;
+ }
+ mCurrentReturnData->clientTargetProperty.pixelFormat = static_cast<PixelFormat>(readSigned());
+ mCurrentReturnData->clientTargetProperty.dataspace = static_cast<Dataspace>(readSigned());
+ return true;
+}
+
+void CommandReader::resetData() {
+ mErrors.clear();
+
+ for (auto& data : mReturnData) {
+ if (data.second.presentFence >= 0) {
+ close(data.second.presentFence);
+ }
+ for (auto fence : data.second.releaseFences) {
+ if (fence >= 0) {
+ close(fence);
+ }
+ }
+ }
+
+ mReturnData.clear();
+ mCurrentReturnData = nullptr;
+}
+
+std::vector<CommandReader::CommandError> CommandReader::takeErrors() {
+ return std::move(mErrors);
+}
+
+bool CommandReader::hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
+ uint32_t* outNumLayerRequestMasks) const {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *outNumChangedCompositionTypes = 0;
+ *outNumLayerRequestMasks = 0;
+ return false;
+ }
+
+ const ReturnData& data = found->second;
+
+ *outNumChangedCompositionTypes = data.compositionTypes.size();
+ *outNumLayerRequestMasks = data.requestMasks.size();
+
+ return !(data.compositionTypes.empty() && data.requestMasks.empty());
+}
+
+void CommandReader::takeChangedCompositionTypes(
+ Display display, std::vector<Layer>* outLayers,
+ std::vector<IComposerClient::Composition>* outTypes) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ outLayers->clear();
+ outTypes->clear();
+ return;
+ }
+
+ ReturnData& data = found->second;
+
+ *outLayers = std::move(data.changedLayers);
+ *outTypes = std::move(data.compositionTypes);
+}
+
+void CommandReader::takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outLayers,
+ std::vector<uint32_t>* outLayerRequestMasks) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *outDisplayRequestMask = 0;
+ outLayers->clear();
+ outLayerRequestMasks->clear();
+ return;
+ }
+
+ ReturnData& data = found->second;
+
+ *outDisplayRequestMask = data.displayRequests;
+ *outLayers = std::move(data.requestedLayers);
+ *outLayerRequestMasks = std::move(data.requestMasks);
+}
+
+void CommandReader::takeReleaseFences(Display display, std::vector<Layer>* outLayers,
+ std::vector<int>* outReleaseFences) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ outLayers->clear();
+ outReleaseFences->clear();
+ return;
+ }
+
+ ReturnData& data = found->second;
+
+ *outLayers = std::move(data.releasedLayers);
+ *outReleaseFences = std::move(data.releaseFences);
+}
+
+void CommandReader::takePresentFence(Display display, int* outPresentFence) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *outPresentFence = -1;
+ return;
+ }
+
+ ReturnData& data = found->second;
+
+ *outPresentFence = data.presentFence;
+ data.presentFence = -1;
+}
+
+void CommandReader::takePresentOrValidateStage(Display display, uint32_t* state) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *state = -1;
+ return;
+ }
+ ReturnData& data = found->second;
+ *state = data.presentOrValidateState;
+}
+
+void CommandReader::takeClientTargetProperty(
+ Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
+ auto found = mReturnData.find(display);
+
+ // If not found, return the default values.
+ if (found == mReturnData.end()) {
+ outClientTargetProperty->pixelFormat = PixelFormat::RGBA_8888;
+ outClientTargetProperty->dataspace = Dataspace::UNKNOWN;
+ return;
+ }
+
+ ReturnData& data = found->second;
+ *outClientTargetProperty = data.clientTargetProperty;
+}
+
+} // namespace Hwc2
+} // 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/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
new file mode 100644
index 0000000..ad253a2
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2016 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 "ComposerHal.h"
+
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+// 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 <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <gui/BufferQueue.h>
+#include <gui/HdrMetadata.h>
+#include <math/mat4.h>
+#include <ui/DisplayedFrameStats.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/StrongPointer.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+
+namespace android::Hwc2 {
+
+namespace types = hardware::graphics::common;
+
+namespace V2_1 = hardware::graphics::composer::V2_1;
+namespace V2_2 = hardware::graphics::composer::V2_2;
+namespace V2_3 = hardware::graphics::composer::V2_3;
+namespace V2_4 = hardware::graphics::composer::V2_4;
+
+using types::V1_0::ColorTransform;
+using types::V1_0::Transform;
+using types::V1_1::RenderIntent;
+using types::V1_2::ColorMode;
+using types::V1_2::Dataspace;
+using types::V1_2::Hdr;
+using types::V1_2::PixelFormat;
+
+using V2_1::Config;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+using V2_4::CommandReaderBase;
+using V2_4::CommandWriterBase;
+using V2_4::IComposer;
+using V2_4::IComposerCallback;
+using V2_4::IComposerClient;
+using V2_4::VsyncPeriodChangeTimeline;
+using V2_4::VsyncPeriodNanos;
+using DisplayCapability = IComposerClient::DisplayCapability;
+using PerFrameMetadata = IComposerClient::PerFrameMetadata;
+using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
+using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob;
+
+class CommandReader : public CommandReaderBase {
+public:
+ ~CommandReader();
+
+ // Parse and execute commands from the command queue. The commands are
+ // actually return values from the server and will be saved in ReturnData.
+ Error parse();
+
+ // Get and clear saved errors.
+ struct CommandError {
+ uint32_t location;
+ Error error;
+ };
+ std::vector<CommandError> takeErrors();
+
+ bool hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
+ uint32_t* outNumLayerRequestMasks) const;
+
+ // Get and clear saved changed composition types.
+ void takeChangedCompositionTypes(Display display, std::vector<Layer>* outLayers,
+ std::vector<IComposerClient::Composition>* outTypes);
+
+ // Get and clear saved display requests.
+ void takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outLayers,
+ std::vector<uint32_t>* outLayerRequestMasks);
+
+ // Get and clear saved release fences.
+ void takeReleaseFences(Display display, std::vector<Layer>* outLayers,
+ std::vector<int>* outReleaseFences);
+
+ // Get and clear saved present fence.
+ void takePresentFence(Display display, int* outPresentFence);
+
+ // Get what stage succeeded during PresentOrValidate: Present or Validate
+ void takePresentOrValidateStage(Display display, uint32_t* state);
+
+ // Get the client target properties requested by hardware composer.
+ void takeClientTargetProperty(Display display,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty);
+
+private:
+ void resetData();
+
+ bool parseSelectDisplay(uint16_t length);
+ bool parseSetError(uint16_t length);
+ bool parseSetChangedCompositionTypes(uint16_t length);
+ bool parseSetDisplayRequests(uint16_t length);
+ bool parseSetPresentFence(uint16_t length);
+ bool parseSetReleaseFences(uint16_t length);
+ bool parseSetPresentOrValidateDisplayResult(uint16_t length);
+ bool parseSetClientTargetProperty(uint16_t length);
+
+ struct ReturnData {
+ uint32_t displayRequests = 0;
+
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+
+ int presentFence = -1;
+
+ std::vector<Layer> releasedLayers;
+ std::vector<int> releaseFences;
+
+ uint32_t presentOrValidateState;
+
+ // Composer 2.4 implementation can return a client target property
+ // structure to indicate the client target properties that hardware
+ // composer requests. The composer client must change the client target
+ // properties to match this request.
+ IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
+ Dataspace::UNKNOWN};
+ };
+
+ std::vector<CommandError> mErrors;
+ std::unordered_map<Display, ReturnData> mReturnData;
+
+ // When SELECT_DISPLAY is parsed, this is updated to point to the
+ // display's return data in mReturnData. We use it to avoid repeated
+ // map lookups.
+ ReturnData* mCurrentReturnData;
+};
+
+// Composer is a wrapper to IComposer, a proxy to server-side composer.
+class HidlComposer final : public Composer {
+public:
+ explicit HidlComposer(const std::string& serviceName);
+ ~HidlComposer() override;
+
+ std::vector<IComposer::Capability> getCapabilities() override;
+ std::string dumpDebugInfo() override;
+
+ void registerCallback(const sp<IComposerCallback>& callback) override;
+
+ // Reset all pending commands in the command buffer. Useful if you want to
+ // skip a frame but have already queued some commands.
+ void resetCommands() override;
+
+ // Explicitly flush all pending commands in the command buffer.
+ Error executeCommands() override;
+
+ uint32_t getMaxVirtualDisplayCount() override;
+ Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+ Display* outDisplay) override;
+ Error destroyVirtualDisplay(Display display) override;
+
+ Error acceptDisplayChanges(Display display) override;
+
+ Error createLayer(Display display, Layer* outLayer) override;
+ Error destroyLayer(Display display, Layer layer) override;
+
+ Error getActiveConfig(Display display, Config* outConfig) override;
+ Error getChangedCompositionTypes(Display display, std::vector<Layer>* outLayers,
+ std::vector<IComposerClient::Composition>* outTypes) override;
+ Error getColorModes(Display display, std::vector<ColorMode>* outModes) override;
+ Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
+ int32_t* outValue) override;
+ Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs);
+ Error getDisplayName(Display display, std::string* outName) override;
+
+ Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outLayers,
+ std::vector<uint32_t>* outLayerRequestMasks) override;
+
+ Error getDozeSupport(Display display, bool* outSupport) override;
+ Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
+ float* outMaxAverageLuminance, float* outMinLuminance) override;
+
+ Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
+ std::vector<int>* outReleaseFences) override;
+
+ Error presentDisplay(Display display, int* outPresentFence) override;
+
+ Error setActiveConfig(Display display, Config config) override;
+
+ /*
+ * The composer caches client targets internally. When target is nullptr,
+ * the composer uses slot to look up the client target from its cache.
+ * When target is not nullptr, the cache is updated with the new target.
+ */
+ Error setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
+ int acquireFence, Dataspace dataspace,
+ const std::vector<IComposerClient::Rect>& damage) override;
+ Error setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) override;
+ Error setColorTransform(Display display, const float* matrix, ColorTransform hint) override;
+ Error setOutputBuffer(Display display, const native_handle_t* buffer,
+ int releaseFence) override;
+ Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
+ Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
+
+ Error setClientTargetSlotCount(Display display) override;
+
+ Error validateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests) override;
+
+ Error presentOrValidateDisplay(Display display, uint32_t* outNumTypes, uint32_t* outNumRequests,
+ int* outPresentFence, uint32_t* state) override;
+
+ Error setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
+ /* see setClientTarget for the purpose of slot */
+ Error setLayerBuffer(Display display, Layer layer, uint32_t slot,
+ const sp<GraphicBuffer>& buffer, int acquireFence) override;
+ Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& damage) override;
+ Error setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) override;
+ Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) override;
+ Error setLayerCompositionType(Display display, Layer layer,
+ IComposerClient::Composition type) override;
+ Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) override;
+ Error setLayerDisplayFrame(Display display, Layer layer,
+ const IComposerClient::Rect& frame) override;
+ Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
+ Error setLayerSidebandStream(Display display, Layer layer,
+ const native_handle_t* stream) override;
+ Error setLayerSourceCrop(Display display, Layer layer,
+ const IComposerClient::FRect& crop) override;
+ Error setLayerTransform(Display display, Layer layer, Transform transform) override;
+ Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& visible) override;
+ Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+
+ // Composer HAL 2.2
+ Error setLayerPerFrameMetadata(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) override;
+ std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(
+ Display display) override;
+ Error getRenderIntents(Display display, ColorMode colorMode,
+ std::vector<RenderIntent>* outRenderIntents) override;
+ Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) override;
+
+ // Composer HAL 2.3
+ Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) override;
+ Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override;
+ Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace,
+ uint8_t* outComponentMask) override;
+ Error setDisplayContentSamplingEnabled(Display display, bool enabled, uint8_t componentMask,
+ uint64_t maxFrames) override;
+ Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
+ DisplayedFrameStats* outStats) override;
+ Error setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
+ Error setDisplayBrightness(Display display, float brightness) override;
+
+ // Composer HAL 2.4
+ bool isVsyncPeriodSwitchSupported() override { return mClient_2_4 != nullptr; }
+ Error getDisplayCapabilities(Display display,
+ std::vector<DisplayCapability>* outCapabilities) override;
+ V2_4::Error getDisplayConnectionType(Display display,
+ IComposerClient::DisplayConnectionType* outType) override;
+ V2_4::Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override;
+ V2_4::Error setActiveConfigWithConstraints(
+ Display display, Config config,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ VsyncPeriodChangeTimeline* outTimeline) override;
+ V2_4::Error setAutoLowLatencyMode(Display displayId, bool on) override;
+ V2_4::Error getSupportedContentTypes(
+ Display displayId,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
+ V2_4::Error setContentType(Display displayId,
+ IComposerClient::ContentType contentType) override;
+ V2_4::Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ 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) override;
+
+private:
+ class CommandWriter : public CommandWriterBase {
+ public:
+ explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {}
+ ~CommandWriter() override {}
+ };
+
+ // Many public functions above simply write a command into the command
+ // queue to batch the calls. validateDisplay and presentDisplay will call
+ // this function to execute the command queue.
+ Error execute();
+
+ sp<V2_1::IComposer> mComposer;
+
+ sp<V2_1::IComposerClient> mClient;
+ sp<V2_2::IComposerClient> mClient_2_2;
+ sp<V2_3::IComposerClient> mClient_2_3;
+ sp<IComposerClient> mClient_2_4;
+
+ // 64KiB minus a small space for metadata such as read/write pointers
+ static constexpr size_t kWriterInitialSize = 64 * 1024 / sizeof(uint32_t) - 16;
+ // Max number of buffers that may be cached for a given layer
+ // We obtain this number by:
+ // 1. Tightly coupling this cache to the max size of BufferQueue
+ // 2. Adding an additional slot for the layer caching feature in SurfaceFlinger (see: Planner.h)
+ static const constexpr uint32_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
+ CommandWriter mWriter;
+ CommandReader mReader;
+};
+
+} // namespace android::Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 1765caf..5c2390e 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -19,7 +19,10 @@
#undef LOG_TAG
#define LOG_TAG "PowerAdvisor"
+#include <unistd.h>
#include <cinttypes>
+#include <cstdint>
+#include <optional>
#include <android-base/properties.h>
#include <utils/Log.h>
@@ -27,6 +30,9 @@
#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>
+
#include <binder/IServiceManager.h>
#include "../SurfaceFlingerProperties.h"
@@ -47,10 +53,14 @@
using android::hardware::power::Boost;
using android::hardware::power::IPower;
+using android::hardware::power::IPowerHintSession;
using android::hardware::power::Mode;
-using base::GetIntProperty;
+using android::hardware::power::WorkDuration;
+
using scheduler::OneShotTimer;
+class AidlPowerHalWrapper;
+
PowerAdvisor::~PowerAdvisor() = default;
namespace {
@@ -83,6 +93,13 @@
void PowerAdvisor::onBootFinished() {
mBootFinished.store(true);
+ {
+ std::lock_guard lock(mPowerHalMutex);
+ HalWrapper* halWrapper = getPowerHal();
+ if (halWrapper != nullptr && usePowerHintSession()) {
+ mPowerHintSessionRunning = halWrapper->startPowerHintSession();
+ }
+ }
}
void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
@@ -136,6 +153,80 @@
}
}
+// checks both if it supports and if it's enabled
+bool PowerAdvisor::usePowerHintSession() {
+ // uses cached value since the underlying support and flag are unlikely to change at runtime
+ ALOGE_IF(!mPowerHintEnabled.has_value(), "Power hint session cannot be used before boot!");
+ return mPowerHintEnabled.value_or(false) && supportsPowerHintSession();
+}
+
+bool PowerAdvisor::supportsPowerHintSession() {
+ // cache to avoid needing lock every time
+ if (!mSupportsPowerHint.has_value()) {
+ std::lock_guard lock(mPowerHalMutex);
+ HalWrapper* const halWrapper = getPowerHal();
+ mSupportsPowerHint = halWrapper->supportsPowerHintSession();
+ }
+ return *mSupportsPowerHint;
+}
+
+bool PowerAdvisor::isPowerHintSessionRunning() {
+ return mPowerHintSessionRunning;
+}
+
+void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) {
+ // we check "supports" here not "usePowerHintSession" because this needs to work
+ // before the session is actually running, and "use" will always fail before boot
+ // we store the values passed in before boot to start the session with during onBootFinished
+ if (!supportsPowerHintSession()) {
+ ALOGV("Power hint session target duration cannot be set, skipping");
+ return;
+ }
+ {
+ std::lock_guard lock(mPowerHalMutex);
+ HalWrapper* const halWrapper = getPowerHal();
+ if (halWrapper != nullptr) {
+ halWrapper->setTargetWorkDuration(targetDurationNanos);
+ }
+ }
+}
+
+void PowerAdvisor::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) {
+ // we check "supports" here not "usePowerHintSession" because this needs to wsork
+ // before the session is actually running, and "use" will always fail before boot.
+ // we store the values passed in before boot to start the session with during onBootFinished
+ if (!supportsPowerHintSession()) {
+ ALOGV("Power hint session thread ids cannot be set, skipping");
+ return;
+ }
+ {
+ std::lock_guard lock(mPowerHalMutex);
+ HalWrapper* const halWrapper = getPowerHal();
+ if (halWrapper != nullptr) {
+ halWrapper->setPowerHintSessionThreadIds(const_cast<std::vector<int32_t>&>(threadIds));
+ }
+ }
+}
+
+void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) {
+ if (!mBootFinished || !usePowerHintSession()) {
+ ALOGV("Actual work duration power hint cannot be sent, skipping");
+ return;
+ }
+ {
+ std::lock_guard lock(mPowerHalMutex);
+ HalWrapper* const halWrapper = getPowerHal();
+ if (halWrapper != nullptr) {
+ halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos);
+ }
+ }
+}
+
+// needs to be set after the flag is known but before PowerAdvisor enters onBootFinished
+void PowerAdvisor::enablePowerHint(bool enabled) {
+ mPowerHintEnabled = enabled;
+}
+
class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
public:
HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
@@ -178,6 +269,26 @@
return true;
}
+ bool supportsPowerHintSession() override { return false; }
+
+ bool isPowerHintSessionRunning() override { return false; }
+
+ void restartPowerHintSession() override {}
+
+ void setPowerHintSessionThreadIds(const std::vector<int32_t>&) override {}
+
+ bool startPowerHintSession() override { return false; }
+
+ void setTargetWorkDuration(int64_t) override {}
+
+ void sendActualWorkDuration(int64_t, nsecs_t) override {}
+
+ bool shouldReconnectHAL() override { return false; }
+
+ std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; }
+
+ std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; }
+
private:
const sp<V1_3::IPower> mPowerHal = nullptr;
};
@@ -195,9 +306,21 @@
if (!ret.isOk()) {
mHasDisplayUpdateImminent = false;
}
+
+ // This just gives a number not a binder status, so no .isOk()
+ mSupportsPowerHints = mPowerHal->getInterfaceVersion() >= 2;
+
+ if (mSupportsPowerHints) {
+ mPowerHintQueue.reserve(MAX_QUEUE_SIZE);
+ }
}
- ~AidlPowerHalWrapper() override = default;
+ ~AidlPowerHalWrapper() override {
+ if (mPowerHintSession != nullptr) {
+ mPowerHintSession->close();
+ mPowerHintSession = nullptr;
+ }
+ };
static std::unique_ptr<HalWrapper> connect() {
// This only waits if the service is actually declared
@@ -232,10 +355,147 @@
return ret.isOk();
}
+ // only version 2+ of the aidl supports power hint sessions, hidl has no support
+ bool supportsPowerHintSession() override { return mSupportsPowerHints; }
+
+ 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 || !mPowerHintTargetDuration.has_value() ||
+ mPowerHintThreadIds.empty()) {
+ ALOGV("Cannot start power hint session, skipping");
+ return false;
+ }
+ auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
+ mPowerHintThreadIds, *mPowerHintTargetDuration,
+ &mPowerHintSession);
+ if (!ret.isOk()) {
+ ALOGW("Failed to start power hint session with error: %s",
+ ret.exceptionToString(ret.exceptionCode()).c_str());
+ // Indicate to the poweradvisor that this wrapper likely needs to be remade
+ mShouldReconnectHal = true;
+ }
+ return isPowerHintSessionRunning();
+ }
+
+ bool shouldSetTargetDuration(int64_t targetDurationNanos) {
+ if (!mLastTargetDurationSent.has_value()) {
+ return true;
+ }
+
+ // report if the change in target from our last submission to now exceeds the threshold
+ return abs(1.0 -
+ static_cast<double>(*mLastTargetDurationSent) /
+ static_cast<double>(targetDurationNanos)) >=
+ ALLOWED_TARGET_DEVIATION_PERCENT;
+ }
+
+ void setTargetWorkDuration(int64_t targetDurationNanos) override {
+ mPowerHintTargetDuration = targetDurationNanos;
+ if (shouldSetTargetDuration(targetDurationNanos) && isPowerHintSessionRunning()) {
+ 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 have exceeded the max queue size
+ if (!mLastMessageReported.has_value() || mPowerHintQueue.size() >= MAX_QUEUE_SIZE) {
+ return true;
+ }
+
+ // duration of most recent timing
+ const double mostRecentActualDuration =
+ static_cast<double>(mPowerHintQueue.back().durationNanos);
+ // duration of the last timing actually reported to the powerhal
+ const double lastReportedActualDuration =
+ static_cast<double>(mLastMessageReported->durationNanos);
+
+ // report if the change in duration from then to now exceeds the threshold
+ return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
+ ALLOWED_ACTUAL_DEVIATION_PERCENT;
+ }
+
+ void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
+ if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
+ ALOGV("Failed to send actual work duration, skipping");
+ return;
+ }
+
+ WorkDuration duration;
+ duration.durationNanos = actualDurationNanos;
+ duration.timeStampNanos = timeStampNanos;
+ mPowerHintQueue.push_back(duration);
+
+ // 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()) {
+ 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();
+ mLastMessageReported = duration;
+ }
+ }
+
+ bool shouldReconnectHAL() override { return mShouldReconnectHal; }
+
+ std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
+
+ std::optional<int64_t> getTargetWorkDuration() override { return mPowerHintTargetDuration; }
+
private:
+ // max number of messages allowed in mPowerHintQueue before reporting is forced
+ static constexpr int32_t MAX_QUEUE_SIZE = 15;
+ // max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
+ static constexpr double ALLOWED_ACTUAL_DEVIATION_PERCENT = 0.1;
+ // max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
+ static constexpr double ALLOWED_TARGET_DEVIATION_PERCENT = 0.05;
+
const sp<IPower> mPowerHal = nullptr;
bool mHasExpensiveRendering = false;
bool mHasDisplayUpdateImminent = false;
+ bool mShouldReconnectHal = false; // used to indicate an error state and need for reconstruction
+ // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
+ sp<IPowerHintSession> mPowerHintSession = nullptr;
+ std::vector<WorkDuration> mPowerHintQueue;
+ // halwrapper owns these values so we can init when we want and reconnect if broken
+ std::optional<int64_t> mPowerHintTargetDuration;
+ std::vector<int32_t> mPowerHintThreadIds;
+ // keep track of the last messages sent for rate limiter change detection
+ std::optional<WorkDuration> mLastMessageReported;
+ std::optional<int64_t> mLastTargetDurationSent;
+ bool mSupportsPowerHints;
};
PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
@@ -246,6 +506,15 @@
return nullptr;
}
+ // grab old hint session values before we destroy any existing wrapper
+ std::vector<int32_t> oldPowerHintSessionThreadIds;
+ std::optional<int64_t> oldTargetWorkDuration;
+
+ if (sHalWrapper != nullptr) {
+ oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds();
+ oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration();
+ }
+
// If we used to have a HAL, but it stopped responding, attempt to reconnect
if (mReconnectPowerHal) {
sHalWrapper = nullptr;
@@ -253,15 +522,34 @@
}
if (sHalWrapper != nullptr) {
- return sHalWrapper.get();
+ auto wrapper = sHalWrapper.get();
+ // if the wrapper is fine, return it, but if it indicates a reconnect, remake it
+ if (!wrapper->shouldReconnectHAL()) {
+ return wrapper;
+ }
+ sHalWrapper = nullptr;
}
+ // at this point, we know for sure there is no running session
+ mPowerHintSessionRunning = false;
+
// First attempt to connect to the AIDL Power HAL
sHalWrapper = AidlPowerHalWrapper::connect();
// 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
+ // thread ids always safe to set
+ sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
+ // only set duration and start if duration is defined
+ if (oldTargetWorkDuration.has_value()) {
+ sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
+ // only start if possible to run and both threadids and duration are defined
+ if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
+ mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
+ }
+ }
}
// If we make it to this point and still don't have a HAL, it's unlikely we
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index f2d0766..b8fd17d 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -40,6 +40,13 @@
virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
virtual bool isUsingExpensiveRendering() = 0;
virtual void notifyDisplayUpdateImminent() = 0;
+ virtual bool usePowerHintSession() = 0;
+ virtual bool supportsPowerHintSession() = 0;
+ virtual bool isPowerHintSessionRunning() = 0;
+ virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
+ virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
+ virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) = 0;
+ virtual void enablePowerHint(bool enabled) = 0;
};
namespace impl {
@@ -54,6 +61,17 @@
virtual bool setExpensiveRendering(bool enabled) = 0;
virtual bool notifyDisplayUpdateImminent() = 0;
+ virtual bool supportsPowerHintSession() = 0;
+ virtual bool isPowerHintSessionRunning() = 0;
+ virtual void restartPowerHintSession() = 0;
+ virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
+ virtual bool startPowerHintSession() = 0;
+ virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
+ virtual void sendActualWorkDuration(int64_t actualDurationNanos,
+ nsecs_t timeStampNanos) = 0;
+ virtual bool shouldReconnectHAL() = 0;
+ virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0;
+ virtual std::optional<int64_t> getTargetWorkDuration() = 0;
};
PowerAdvisor(SurfaceFlinger& flinger);
@@ -62,8 +80,15 @@
void init() override;
void onBootFinished() override;
void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
- bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; }
+ bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; };
void notifyDisplayUpdateImminent() override;
+ bool usePowerHintSession() override;
+ bool supportsPowerHintSession() override;
+ bool isPowerHintSessionRunning() override;
+ void setTargetWorkDuration(int64_t targetDurationNanos) override;
+ void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
+ void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) override;
+ void enablePowerHint(bool enabled) override;
private:
HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
@@ -71,6 +96,9 @@
std::mutex mPowerHalMutex;
std::atomic_bool mBootFinished = false;
+ std::optional<bool> mPowerHintEnabled;
+ std::optional<bool> mSupportsPowerHint;
+ bool mPowerHintSessionRunning = false;
std::unordered_set<DisplayId> mExpensiveDisplays;
bool mNotifiedExpensiveRendering = false;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index e26ab11..82a9ae2 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -326,7 +326,7 @@
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
- LOG_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId));
+ LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
status_t result =
mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
@@ -641,7 +641,7 @@
}
status_t VirtualDisplaySurface::refreshOutputBuffer() {
- LOG_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId));
+ LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
if (mOutputProducerSlot >= 0) {
mSource[SOURCE_SINK]->cancelBuffer(
diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h
index e9f06e5..639b3e5 100644
--- a/services/surfaceflinger/Fps.h
+++ b/services/surfaceflinger/Fps.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,94 +19,110 @@
#include <cmath>
#include <ostream>
#include <string>
+#include <type_traits>
#include <android-base/stringprintf.h>
#include <utils/Timers.h>
namespace android {
-// Value which represents "frames per second". This class is a wrapper around
-// float, providing some useful utilities, such as comparisons with tolerance
-// and converting between period duration and frequency.
+// Frames per second, stored as floating-point frequency. Provides conversion from/to period in
+// nanoseconds, and relational operators with precision threshold.
+//
+// const Fps fps = 60_Hz;
+//
+// using namespace fps_approx_ops;
+// assert(fps == Fps::fromPeriodNsecs(16'666'667));
+//
class Fps {
public:
- static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); }
+ constexpr Fps() = default;
- Fps() = default;
- explicit constexpr Fps(float fps)
- : fps(fps), period(fps == 0.0f ? 0 : static_cast<nsecs_t>(1e9f / fps)) {}
-
- constexpr float getValue() const { return fps; }
-
- constexpr nsecs_t getPeriodNsecs() const { return period; }
-
- bool equalsWithMargin(const Fps& other) const { return std::abs(fps - other.fps) < kMargin; }
-
- // DO NOT use for std::sort. Instead use comparesLess().
- bool lessThanWithMargin(const Fps& other) const { return fps + kMargin < other.fps; }
-
- bool greaterThanWithMargin(const Fps& other) const { return fps > other.fps + kMargin; }
-
- bool lessThanOrEqualWithMargin(const Fps& other) const { return !greaterThanWithMargin(other); }
-
- bool greaterThanOrEqualWithMargin(const Fps& other) const { return !lessThanWithMargin(other); }
-
- bool isValid() const { return fps > 0.0f; }
-
- int getIntValue() const { return static_cast<int>(std::round(fps)); }
-
- // Use this comparator for sorting. Using a comparator with margins can
- // cause std::sort to crash.
- inline static bool comparesLess(const Fps& left, const Fps& right) {
- return left.fps < right.fps;
+ static constexpr Fps fromValue(float frequency) {
+ return frequency > 0.f ? Fps(frequency, static_cast<nsecs_t>(1e9f / frequency)) : Fps();
}
- // Compares two FPS with margin.
- // Transitivity is not guaranteed, i.e. a==b and b==c doesn't imply a==c.
- // DO NOT use with hash maps. Instead use EqualsInBuckets.
- struct EqualsWithMargin {
- bool operator()(const Fps& left, const Fps& right) const {
- return left.equalsWithMargin(right);
- }
- };
-
- // Equals comparator which can be used with hash maps.
- // It's guaranteed that if two elements are equal, then their hashes are equal.
- struct EqualsInBuckets {
- bool operator()(const Fps& left, const Fps& right) const {
- return left.getBucket() == right.getBucket();
- }
- };
-
- inline friend std::string to_string(const Fps& fps) {
- return base::StringPrintf("%.2ffps", fps.fps);
+ static constexpr Fps fromPeriodNsecs(nsecs_t period) {
+ return period > 0 ? Fps(1e9f / period, period) : Fps();
}
- inline friend std::ostream& operator<<(std::ostream& os, const Fps& fps) {
- return os << to_string(fps);
- }
+ constexpr bool isValid() const { return mFrequency > 0.f; }
+
+ constexpr float getValue() const { return mFrequency; }
+ int getIntValue() const { return static_cast<int>(std::round(mFrequency)); }
+
+ constexpr nsecs_t getPeriodNsecs() const { return mPeriod; }
private:
- friend std::hash<android::Fps>;
+ constexpr Fps(float frequency, nsecs_t period) : mFrequency(frequency), mPeriod(period) {}
- constexpr Fps(float fps, nsecs_t period) : fps(fps), period(period) {}
-
- float getBucket() const { return std::round(fps / kMargin); }
-
- static constexpr float kMargin = 0.001f;
- float fps = 0;
- nsecs_t period = 0;
+ float mFrequency = 0.f;
+ nsecs_t mPeriod = 0;
};
static_assert(std::is_trivially_copyable_v<Fps>);
-} // namespace android
+constexpr Fps operator""_Hz(unsigned long long frequency) {
+ return Fps::fromValue(static_cast<float>(frequency));
+}
-namespace std {
-template <>
-struct hash<android::Fps> {
- std::size_t operator()(const android::Fps& fps) const {
- return std::hash<float>()(fps.getBucket());
- }
+constexpr Fps operator""_Hz(long double frequency) {
+ return Fps::fromValue(static_cast<float>(frequency));
+}
+
+inline bool isStrictlyLess(Fps lhs, Fps rhs) {
+ return lhs.getValue() < rhs.getValue();
+}
+
+// Does not satisfy equivalence relation.
+inline bool isApproxEqual(Fps lhs, Fps rhs) {
+ // TODO(b/185536303): Replace with ULP distance.
+ return std::abs(lhs.getValue() - rhs.getValue()) < 0.001f;
+}
+
+// Does not satisfy strict weak order.
+inline bool isApproxLess(Fps lhs, Fps rhs) {
+ return isStrictlyLess(lhs, rhs) && !isApproxEqual(lhs, rhs);
+}
+
+namespace fps_approx_ops {
+
+inline bool operator==(Fps lhs, Fps rhs) {
+ return isApproxEqual(lhs, rhs);
+}
+
+inline bool operator<(Fps lhs, Fps rhs) {
+ return isApproxLess(lhs, rhs);
+}
+
+inline bool operator!=(Fps lhs, Fps rhs) {
+ return !isApproxEqual(lhs, rhs);
+}
+
+inline bool operator>(Fps lhs, Fps rhs) {
+ return isApproxLess(rhs, lhs);
+}
+
+inline bool operator<=(Fps lhs, Fps rhs) {
+ return !isApproxLess(rhs, lhs);
+}
+
+inline bool operator>=(Fps lhs, Fps rhs) {
+ return !isApproxLess(lhs, rhs);
+}
+
+} // namespace fps_approx_ops
+
+struct FpsApproxEqual {
+ bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); }
};
-} // namespace std
\ No newline at end of file
+
+inline std::string to_string(Fps fps) {
+ return base::StringPrintf("%.2f Hz", fps.getValue());
+}
+
+inline std::ostream& operator<<(std::ostream& stream, Fps fps) {
+ return stream << to_string(fps);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/FpsReporter.h b/services/surfaceflinger/FpsReporter.h
index bd7b9a5..438b1aa 100644
--- a/services/surfaceflinger/FpsReporter.h
+++ b/services/surfaceflinger/FpsReporter.h
@@ -24,6 +24,7 @@
#include "Clock.h"
#include "FrameTimeline/FrameTimeline.h"
+#include "WpHash.h"
namespace android {
@@ -50,11 +51,6 @@
private:
mutable std::mutex mMutex;
- struct WpHash {
- size_t operator()(const wp<IBinder>& p) const {
- return std::hash<IBinder*>()(p.unsafe_get());
- }
- };
struct TrackedListener {
sp<gui::IFpsListener> listener;
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.h b/services/surfaceflinger/HdrLayerInfoReporter.h
index 671395f..4ada2b6 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.h
+++ b/services/surfaceflinger/HdrLayerInfoReporter.h
@@ -22,6 +22,8 @@
#include <unordered_map>
+#include "WpHash.h"
+
namespace android {
class HdrLayerInfoReporter final : public IBinder::DeathRecipient {
@@ -63,11 +65,6 @@
private:
mutable std::mutex mMutex;
- struct WpHash {
- size_t operator()(const wp<IBinder>& p) const {
- return std::hash<IBinder*>()(p.unsafe_get());
- }
- };
struct TrackedListener {
sp<gui::IHdrLayerInfoListener> listener;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d8854d3..d85e843 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -88,7 +88,7 @@
Layer::Layer(const LayerCreationArgs& args)
: mFlinger(args.flinger),
- mName(args.name),
+ mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
mClientRef(args.client),
mWindowType(
static_cast<WindowInfo::Type>(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) {
@@ -179,23 +179,9 @@
if (mDrawingState.sidebandStream != nullptr) {
mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
}
-
if (mHadClonedChild) {
mFlinger->mNumClones--;
}
-
- for (auto const& child : mCurrentChildren) {
- if (child->mCurrentParent == this) child->mCurrentParent = nullptr;
- if (child->mDrawingParent == this) {
- child->mDrawingParent = nullptr;
- }
- }
- for (auto const& child : mDrawingChildren) {
- if (child->mCurrentParent == this) child->mCurrentParent = nullptr;
- if (child->mDrawingParent == this) {
- child->mDrawingParent = nullptr;
- }
- }
}
LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, std::string name,
@@ -252,7 +238,7 @@
}
sp<Layer> Layer::getRootLayer() {
- auto parent = getParent();
+ sp<Layer> parent = getParent();
if (parent == nullptr) {
return this;
}
@@ -434,8 +420,6 @@
compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
compositionState->alpha = alpha;
- compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
- compositionState->blurRegions = drawingState.blurRegions;
compositionState->stretchEffect = getStretchEffect();
}
@@ -497,6 +481,9 @@
compositionState->stretchEffect.hasEffect()) {
compositionState->forceClientComposition = true;
}
+ // If there are no visible region changes, we still need to update blur parameters.
+ compositionState->blurRegions = drawingState.blurRegions;
+ compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
}
void Layer::prepareCursorCompositionState() {
@@ -677,7 +664,7 @@
return true;
}
- const auto p = mDrawingParent;
+ const auto p = mDrawingParent.promote();
return (p != nullptr) ? p->isSecure() : false;
}
@@ -860,7 +847,7 @@
if (getDrawingState().isTrustedOverlay) {
return true;
}
- const auto p = mDrawingParent;
+ const auto& p = mDrawingParent.promote();
return (p != nullptr) && p->isTrustedOverlay();
}
@@ -937,8 +924,11 @@
bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) {
if (mDrawingState.backgroundBlurRadius == backgroundBlurRadius) return false;
-
- mDrawingState.sequence++;
+ // If we start or stop drawing blur then the layer's visibility state may change so increment
+ // the magic sequence number.
+ if (mDrawingState.backgroundBlurRadius == 0 || backgroundBlurRadius == 0) {
+ mDrawingState.sequence++;
+ }
mDrawingState.backgroundBlurRadius = backgroundBlurRadius;
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -971,6 +961,11 @@
}
bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
+ // If we start or stop drawing blur then the layer's visibility state may change so increment
+ // the magic sequence number.
+ if (mDrawingState.blurRegions.size() == 0 || blurRegions.size() == 0) {
+ mDrawingState.sequence++;
+ }
mDrawingState.blurRegions = blurRegions;
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -1040,7 +1035,7 @@
return mDrawingState.frameRateSelectionPriority;
}
// If not, search whether its parents have it set.
- auto parent = getParent();
+ sp<Layer> parent = getParent();
if (parent != nullptr) {
return parent->getFrameRateSelectionPriority();
}
@@ -1053,11 +1048,10 @@
};
ui::LayerStack Layer::getLayerStack() const {
- auto p = mDrawingParent;
- if (p == nullptr) {
- return getDrawingState().layerStack;
+ if (const auto parent = mDrawingParent.promote()) {
+ return parent->getLayerStack();
}
- return mDrawingParent->getLayerStack();
+ return getDrawingState().layerStack;
}
bool Layer::setShadowRadius(float shadowRadius) {
@@ -1102,7 +1096,7 @@
return mDrawingState.stretchEffect;
}
- auto parent = mDrawingParent;
+ sp<Layer> parent = getParent();
if (parent != nullptr) {
auto effect = parent->getStretchEffect();
if (effect.hasEffect()) {
@@ -1138,7 +1132,7 @@
if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote &&
childrenHaveFrameRate) {
*transactionNeeded |=
- setFrameRateForLayerTree(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote));
+ setFrameRateForLayerTree(FrameRate(Fps(), FrameRateCompatibility::NoVote));
}
// We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for
@@ -1172,9 +1166,6 @@
}
bool Layer::setFrameRate(FrameRate frameRate) {
- if (!mFlinger->useFrameRateApi) {
- return false;
- }
if (mDrawingState.frameRate == frameRate) {
return false;
}
@@ -1317,7 +1308,7 @@
bool Layer::isHiddenByPolicy() const {
const State& s(mDrawingState);
- auto parent = mDrawingParent;
+ const auto& parent = mDrawingParent.promote();
if (parent != nullptr && parent->isHiddenByPolicy()) {
return true;
}
@@ -1364,7 +1355,7 @@
LayerDebugInfo info;
const State& ds = getDrawingState();
info.mName = getName();
- auto parent = mDrawingParent;
+ sp<Layer> parent = mDrawingParent.promote();
info.mParentName = parent ? parent->getName() : "none"s;
info.mType = getType();
info.mTransparentRegion = ds.activeTransparentRegion_legacy;
@@ -1596,7 +1587,7 @@
void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
for (const sp<Layer>& child : mDrawingChildren) {
- child->mDrawingParent = newParent.get();
+ child->mDrawingParent = newParent;
child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
newParent->mEffectiveShadowRadius);
}
@@ -1616,7 +1607,7 @@
}
}
- auto parent = getParent();
+ sp<Layer> parent = getParent();
if (parent != nullptr) {
parent->removeChild(this);
}
@@ -1651,7 +1642,7 @@
mat4 Layer::getColorTransform() const {
mat4 colorTransform = mat4(getDrawingState().colorTransform);
- if (auto parent = mDrawingParent; parent != nullptr) {
+ if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
colorTransform = parent->getColorTransform() * colorTransform;
}
return colorTransform;
@@ -1659,7 +1650,7 @@
bool Layer::hasColorTransform() const {
bool hasColorTransform = getDrawingState().hasColorTransform;
- if (auto parent = mDrawingParent; parent != nullptr) {
+ if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
hasColorTransform = hasColorTransform || parent->hasColorTransform();
}
return hasColorTransform;
@@ -1673,7 +1664,7 @@
}
void Layer::setParent(const sp<Layer>& layer) {
- mCurrentParent = layer.get();
+ mCurrentParent = layer;
}
int32_t Layer::getZ(LayerVector::StateSet) const {
@@ -1877,7 +1868,7 @@
}
half Layer::getAlpha() const {
- auto p = mDrawingParent;
+ const auto& p = mDrawingParent.promote();
half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
return parentAlpha * getDrawingState().color.a;
@@ -1888,7 +1879,7 @@
if (fixedTransformHint != ui::Transform::ROT_INVALID) {
return fixedTransformHint;
}
- auto p = mCurrentParent;
+ const auto& p = mCurrentParent.promote();
if (!p) return fixedTransformHint;
return p->getFixedTransformHint();
}
@@ -1899,7 +1890,7 @@
}
int32_t Layer::getBackgroundBlurRadius() const {
- auto p = mDrawingParent;
+ const auto& p = mDrawingParent.promote();
half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
return parentAlpha * getDrawingState().backgroundBlurRadius;
@@ -1917,8 +1908,9 @@
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
// Get parent settings
RoundedCornerState parentSettings;
- if (mDrawingParent != nullptr) {
- parentSettings = mDrawingParent->getRoundedCornerState();
+ const auto& parent = mDrawingParent.promote();
+ if (parent != nullptr) {
+ parentSettings = parent->getRoundedCornerState();
if (parentSettings.radius > 0) {
ui::Transform t = getActiveTransform(getDrawingState());
t = t.inverse();
@@ -2134,7 +2126,7 @@
LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
layerInfo->mutable_requested_transform());
- auto parent = useDrawing ? mDrawingParent : mCurrentParent;
+ auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
if (parent != nullptr) {
layerInfo->set_parent(parent->sequence);
} else {
@@ -2281,9 +2273,9 @@
}
void Layer::fillTouchOcclusionMode(WindowInfo& info) {
- Layer* p = this;
+ sp<Layer> p = this;
while (p != nullptr && !p->hasInputInfo()) {
- p = p->mDrawingParent;
+ p = p->mDrawingParent.promote();
}
if (p != nullptr) {
info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode;
@@ -2295,8 +2287,9 @@
if (mode == gui::DropInputMode::ALL) {
return mode;
}
- if (mDrawingParent) {
- gui::DropInputMode parentMode = mDrawingParent->getDropInputMode();
+ sp<Layer> parent = mDrawingParent.promote();
+ if (parent) {
+ gui::DropInputMode parentMode = parent->getDropInputMode();
if (parentMode != gui::DropInputMode::NONE) {
return parentMode;
}
@@ -2323,7 +2316,8 @@
}
// Check if the parent has set an alpha on the layer
- if (mDrawingParent && mDrawingParent->getAlpha() != 1.0_hf) {
+ sp<Layer> parent = mDrawingParent.promote();
+ if (parent && parent->getAlpha() != 1.0_hf) {
info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(),
static_cast<float>(getAlpha()));
@@ -2421,10 +2415,10 @@
if (mClonedChild != nullptr) {
return this;
}
- if (mDrawingParent == nullptr) {
+ if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) {
return nullptr;
}
- return mDrawingParent->getClonedRoot();
+ return mDrawingParent.promote()->getClonedRoot();
}
bool Layer::hasInputInfo() const {
@@ -2611,7 +2605,8 @@
return true;
}
- return mDrawingParent && mDrawingParent->isInternalDisplayOverlay();
+ sp<Layer> parent = mDrawingParent.promote();
+ return parent && parent->isInternalDisplayOverlay();
}
void Layer::setClonedChild(const sp<Layer>& clonedChild) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f6f1621..d36b816 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -794,12 +794,12 @@
// Returns index if removed, or negative value otherwise
// for symmetry with Vector::remove
ssize_t removeChild(const sp<Layer>& layer);
+ sp<Layer> getParent() const { return mCurrentParent.promote(); }
// Should be called with the surfaceflinger statelock held
bool isAtRoot() const { return mIsAtRoot; }
void setIsAtRoot(bool isAtRoot) { mIsAtRoot = isAtRoot; }
- Layer* getParent() const { return mCurrentParent; }
bool hasParent() const { return getParent() != nullptr; }
Rect getScreenBounds(bool reduceTransparentRegion = true) const;
bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
@@ -1006,8 +1006,8 @@
LayerVector mCurrentChildren{LayerVector::StateSet::Current};
LayerVector mDrawingChildren{LayerVector::StateSet::Drawing};
- Layer* mCurrentParent = nullptr;
- Layer* mDrawingParent = nullptr;
+ wp<Layer> mCurrentParent;
+ wp<Layer> mDrawingParent;
// Window types from WindowManager.LayoutParams
const gui::WindowInfo::Type mWindowType;
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index e84508f..11fe6d0 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -94,8 +94,22 @@
// no need to check rotation because there is none
mNeedsFiltering = sourceCrop.width() != getReqWidth() || sourceCrop.height() != getReqHeight();
+ // If layer is offscreen, update mirroring info if it exists
+ if (mLayer->isRemovedFromCurrentState()) {
+ mLayer->traverse(LayerVector::StateSet::Drawing,
+ [&](Layer* layer) { layer->updateMirrorInfo(); });
+ mLayer->traverse(LayerVector::StateSet::Drawing,
+ [&](Layer* layer) { layer->updateCloneBufferInfo(); });
+ }
+
if (!mChildrenOnly) {
mTransform = mLayer->getTransform().inverse();
+ // If the layer is offscreen, compute bounds since we don't compute bounds for offscreen
+ // layers in a regular cycles.
+ if (mLayer->isRemovedFromCurrentState()) {
+ FloatRect maxBounds = mFlinger.getMaxDisplayBounds();
+ mLayer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
+ }
drawLayers();
} else {
uint32_t w = static_cast<uint32_t>(getWidth());
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 2231853..f715309 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -30,6 +30,7 @@
#include <unordered_map>
#include "Scheduler/OneShotTimer.h"
+#include "WpHash.h"
namespace android {
@@ -88,11 +89,6 @@
sp<IRegionSamplingListener> listener;
};
- struct WpHash {
- size_t operator()(const wp<IBinder>& p) const {
- return std::hash<IBinder*>()(p.unsafe_get());
- }
- };
std::vector<float> sampleBuffer(
const sp<GraphicBuffer>& buffer, const Point& leftTop,
const std::vector<RegionSamplingThread::Descriptor>& descriptors, uint32_t orientation);
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 8a45b66..314526a 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -41,7 +41,7 @@
: mName(name),
mOwnerUid(ownerUid),
mDefaultVote(defaultVote),
- mLayerVote({defaultVote, Fps(0.0f)}),
+ mLayerVote({defaultVote, Fps()}),
mRefreshRateHistory(name) {}
void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
@@ -93,10 +93,11 @@
return false;
}
+ using fps_approx_ops::operator>=;
+
// Layer is considered frequent if the average frame rate is higher than the threshold
const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
- return Fps::fromPeriodNsecs(totalTime / (numFrames - 1))
- .greaterThanOrEqualWithMargin(kMinFpsForFrequentLayer);
+ return Fps::fromPeriodNsecs(totalTime / (numFrames - 1)) >= kMinFpsForFrequentLayer;
}
bool LayerInfo::isAnimating(nsecs_t now) const {
@@ -191,17 +192,17 @@
return std::nullopt;
}
- const auto averageFrameTime = calculateAverageFrameTime();
- if (averageFrameTime.has_value()) {
+ if (const auto averageFrameTime = calculateAverageFrameTime()) {
const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime);
const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now);
if (refreshRateConsistent) {
const auto knownRefreshRate = refreshRateConfigs.findClosestKnownFrameRate(refreshRate);
- // To avoid oscillation, use the last calculated refresh rate if it is
- // close enough
+ using fps_approx_ops::operator!=;
+
+ // To avoid oscillation, use the last calculated refresh rate if it is close enough.
if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) >
MARGIN &&
- !mLastRefreshRate.reported.equalsWithMargin(knownRefreshRate)) {
+ mLastRefreshRate.reported != knownRefreshRate) {
mLastRefreshRate.calculated = refreshRate;
mLastRefreshRate.reported = knownRefreshRate;
}
@@ -228,15 +229,15 @@
if (isAnimating(now)) {
ALOGV("%s is animating", mName.c_str());
mLastRefreshRate.animatingOrInfrequent = true;
- return {LayerHistory::LayerVoteType::Max, Fps(0.0f)};
+ return {LayerHistory::LayerVoteType::Max, Fps()};
}
if (!isFrequent(now)) {
ALOGV("%s is infrequent", mName.c_str());
mLastRefreshRate.animatingOrInfrequent = true;
- // Infrequent layers vote for mininal refresh rate for
+ // Infrequent layers vote for minimal refresh rate for
// battery saving purposes and also to prevent b/135718869.
- return {LayerHistory::LayerVoteType::Min, Fps(0.0f)};
+ return {LayerHistory::LayerVoteType::Min, Fps()};
}
// If the layer was previously tagged as animating or infrequent, we clear
@@ -253,7 +254,7 @@
}
ALOGV("%s Max (can't resolve refresh rate)", mName.c_str());
- return {LayerHistory::LayerVoteType::Max, Fps(0.0f)};
+ return {LayerHistory::LayerVoteType::Max, Fps()};
}
const char* LayerInfo::getTraceTag(android::scheduler::LayerHistory::LayerVoteType type) const {
@@ -300,9 +301,13 @@
bool LayerInfo::RefreshRateHistory::isConsistent() const {
if (mRefreshRates.empty()) return true;
- const auto max = std::max_element(mRefreshRates.begin(), mRefreshRates.end());
- const auto min = std::min_element(mRefreshRates.begin(), mRefreshRates.end());
- const auto consistent =
+ const auto [min, max] =
+ std::minmax_element(mRefreshRates.begin(), mRefreshRates.end(),
+ [](const auto& lhs, const auto& rhs) {
+ return isStrictlyLess(lhs.refreshRate, rhs.refreshRate);
+ });
+
+ const bool consistent =
max->refreshRate.getValue() - min->refreshRate.getValue() < MARGIN_CONSISTENT_FPS;
if (CC_UNLIKELY(sTraceEnabled)) {
@@ -321,4 +326,4 @@
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index ce9783c..92abbae 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -51,7 +51,7 @@
// is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
// favor of a low refresh rate.
static constexpr size_t kFrequentLayerWindowSize = 3;
- static constexpr Fps kMinFpsForFrequentLayer{10.0f};
+ static constexpr Fps kMinFpsForFrequentLayer = 10_Hz;
static constexpr auto kMaxPeriodForFrequentLayerNs =
std::chrono::nanoseconds(kMinFpsForFrequentLayer.getPeriodNsecs()) + 1ms;
@@ -62,7 +62,7 @@
// Holds information about the layer vote
struct LayerVote {
LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic;
- Fps fps{0.0f};
+ Fps fps;
Seamlessness seamlessness = Seamlessness::Default;
};
@@ -86,19 +86,17 @@
using Seamlessness = scheduler::Seamlessness;
Fps rate;
- FrameRateCompatibility type;
- Seamlessness seamlessness;
+ FrameRateCompatibility type = FrameRateCompatibility::Default;
+ Seamlessness seamlessness = Seamlessness::Default;
- FrameRate()
- : rate(0),
- type(FrameRateCompatibility::Default),
- seamlessness(Seamlessness::Default) {}
+ FrameRate() = default;
+
FrameRate(Fps rate, FrameRateCompatibility type,
Seamlessness seamlessness = Seamlessness::OnlySeamless)
: rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {}
bool operator==(const FrameRate& other) const {
- return rate.equalsWithMargin(other.rate) && type == other.type &&
+ return isApproxEqual(rate, other.rate) && type == other.type &&
seamlessness == other.seamlessness;
}
@@ -151,7 +149,7 @@
void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; }
// Resets the layer vote to its default.
- void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(0.0f), Seamlessness::Default}; }
+ void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(), Seamlessness::Default}; }
std::string getName() const { return mName; }
@@ -201,9 +199,9 @@
// Holds information about the calculated and reported refresh rate
struct RefreshRateHeuristicData {
// Rate calculated on the layer
- Fps calculated{0.0f};
+ Fps calculated;
// Last reported rate for LayerInfo::getRefreshRate()
- Fps reported{0.0f};
+ Fps reported;
// Whether the last reported rate for LayerInfo::getRefreshRate()
// was due to animation or infrequent updates
bool animatingOrInfrequent = false;
@@ -229,14 +227,8 @@
// Holds the refresh rate when it was calculated
struct RefreshRateData {
- Fps refreshRate{0.0f};
+ Fps refreshRate;
nsecs_t timestamp = 0;
-
- bool operator<(const RefreshRateData& other) const {
- // We don't need comparison with margins since we are using
- // this to find the min and max refresh rates.
- return refreshRate.getValue() < other.refreshRate.getValue();
- }
};
// Holds tracing strings
@@ -268,7 +260,7 @@
// Used for sanitizing the heuristic data. If two frames are less than
// this period apart from each other they'll be considered as duplicates.
- static constexpr nsecs_t kMinPeriodBetweenFrames = Fps(240.f).getPeriodNsecs();
+ static constexpr nsecs_t kMinPeriodBetweenFrames = (240_Hz).getPeriodNsecs();
// Used for sanitizing the heuristic data. If two frames are more than
// this period apart from each other, the interval between them won't be
// taken into account when calculating average frame rate.
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index c9f00a0..aabd88a 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -42,19 +42,18 @@
}
std::vector<Fps> constructKnownFrameRates(const DisplayModes& modes) {
- std::vector<Fps> knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)};
+ std::vector<Fps> knownFrameRates = {24_Hz, 30_Hz, 45_Hz, 60_Hz, 72_Hz};
knownFrameRates.reserve(knownFrameRates.size() + modes.size());
- // Add all supported refresh rates to the set
+ // Add all supported refresh rates.
for (const auto& mode : modes) {
- const auto refreshRate = Fps::fromPeriodNsecs(mode->getVsyncPeriod());
- knownFrameRates.emplace_back(refreshRate);
+ knownFrameRates.push_back(Fps::fromPeriodNsecs(mode->getVsyncPeriod()));
}
- // Sort and remove duplicates
- std::sort(knownFrameRates.begin(), knownFrameRates.end(), Fps::comparesLess);
+ // Sort and remove duplicates.
+ std::sort(knownFrameRates.begin(), knownFrameRates.end(), isStrictlyLess);
knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
- Fps::EqualsWithMargin()),
+ isApproxEqual),
knownFrameRates.end());
return knownFrameRates;
}
@@ -64,6 +63,11 @@
using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
using RefreshRate = RefreshRateConfigs::RefreshRate;
+bool RefreshRate::inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
+ using fps_approx_ops::operator<=;
+ return minRefreshRate <= getFps() && getFps() <= maxRefreshRate;
+}
+
std::string RefreshRate::toString() const {
return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
getModeId().value(), mode->getHwcId(), getFps().getValue(),
@@ -110,14 +114,14 @@
bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer,
const RefreshRate& refreshRate) const {
+ using namespace fps_approx_ops;
+
switch (layer.vote) {
case LayerVoteType::ExplicitExactOrMultiple:
case LayerVoteType::Heuristic:
if (mConfig.frameRateMultipleThreshold != 0 &&
- refreshRate.getFps().greaterThanOrEqualWithMargin(
- Fps(mConfig.frameRateMultipleThreshold)) &&
- layer.desiredRefreshRate.lessThanWithMargin(
- Fps(mConfig.frameRateMultipleThreshold / 2))) {
+ refreshRate.getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
+ layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2)) {
// Don't vote high refresh rates past the threshold for layers with a low desired
// refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for
// 120 Hz, but desired 60 fps should have a vote.
@@ -247,7 +251,7 @@
};
RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
- const GlobalSignals& globalSignals,
+ GlobalSignals globalSignals,
GlobalSignals* outSignalsConsidered) const {
std::lock_guard lock(mLock);
@@ -269,7 +273,7 @@
}
std::optional<RefreshRate> RefreshRateConfigs::getCachedBestRefreshRate(
- const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
+ const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals,
GlobalSignals* outSignalsConsidered) const {
const bool sameAsLastCall = lastBestRefreshRateInvocation &&
lastBestRefreshRateInvocation->layerRequirements == layers &&
@@ -286,7 +290,7 @@
}
RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
- const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
+ const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals,
GlobalSignals* outSignalsConsidered) const {
ATRACE_CALL();
ALOGV("getBestRefreshRate %zu layers", layers.size());
@@ -370,7 +374,7 @@
// move out the of range if layers explicitly request a different refresh
// rate.
const bool primaryRangeIsSingleRate =
- policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max);
+ isApproxEqual(policy->primaryRange.min, policy->primaryRange.max);
if (!globalSignals.touch && globalSignals.idle &&
!(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
@@ -498,8 +502,11 @@
return explicitExact == 0;
}
}();
+
+ using fps_approx_ops::operator<;
+
if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
- bestRefreshRate->getFps().lessThanWithMargin(touchRefreshRate.getFps())) {
+ bestRefreshRate->getFps() < touchRefreshRate.getFps()) {
setTouchConsidered();
ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
return touchRefreshRate;
@@ -552,7 +559,8 @@
}
RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides(
- const std::vector<LayerRequirement>& layers, Fps displayFrameRate, bool touch) const {
+ const std::vector<LayerRequirement>& layers, Fps displayFrameRate,
+ GlobalSignals globalSignals) const {
ATRACE_CALL();
if (!mSupportsFrameRateOverride) return {};
@@ -570,7 +578,7 @@
return layer->vote == LayerVoteType::ExplicitExactOrMultiple;
});
- if (touch && hasExplicitExactOrMultiple) {
+ if (globalSignals.touch && hasExplicitExactOrMultiple) {
continue;
}
@@ -798,8 +806,10 @@
ALOGE("Default mode is not in the primary range.");
return false;
}
- return policy.appRequestRange.min.lessThanOrEqualWithMargin(policy.primaryRange.min) &&
- policy.appRequestRange.max.greaterThanOrEqualWithMargin(policy.primaryRange.max);
+
+ using namespace fps_approx_ops;
+ return policy.appRequestRange.min <= policy.primaryRange.min &&
+ policy.appRequestRange.max >= policy.primaryRange.max;
}
status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
@@ -925,19 +935,21 @@
}
Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
- if (frameRate.lessThanOrEqualWithMargin(*mKnownFrameRates.begin())) {
- return *mKnownFrameRates.begin();
+ using namespace fps_approx_ops;
+
+ if (frameRate <= mKnownFrameRates.front()) {
+ return mKnownFrameRates.front();
}
- if (frameRate.greaterThanOrEqualWithMargin(*std::prev(mKnownFrameRates.end()))) {
- return *std::prev(mKnownFrameRates.end());
+ if (frameRate >= mKnownFrameRates.back()) {
+ return mKnownFrameRates.back();
}
auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate,
- Fps::comparesLess);
+ isStrictlyLess);
- const auto distance1 = std::abs((frameRate.getValue() - lowerBound->getValue()));
- const auto distance2 = std::abs((frameRate.getValue() - std::prev(lowerBound)->getValue()));
+ const auto distance1 = std::abs(frameRate.getValue() - lowerBound->getValue());
+ const auto distance2 = std::abs(frameRate.getValue() - std::prev(lowerBound)->getValue());
return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
}
@@ -956,7 +968,7 @@
}
if (minByPolicy == maxByPolicy) {
// when min primary range in display manager policy is below device min turn on the timer.
- if (currentPolicy->primaryRange.min.lessThanWithMargin(deviceMin.getFps())) {
+ if (isApproxLess(currentPolicy->primaryRange.min, deviceMin.getFps())) {
return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
}
return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
@@ -982,14 +994,14 @@
}
bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) {
- if (smaller.getValue() > bigger.getValue()) {
+ if (isStrictlyLess(bigger, smaller)) {
return isFractionalPairOrMultiple(bigger, smaller);
}
const auto multiplier = std::round(bigger.getValue() / smaller.getValue());
constexpr float kCoef = 1000.f / 1001.f;
- return bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier / kCoef)) ||
- bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier * kCoef));
+ return isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier / kCoef)) ||
+ isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef));
}
void RefreshRateConfigs::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 3abf83d..53472ef 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -76,19 +76,15 @@
// Checks whether the fps of this RefreshRate struct is within a given min and max refresh
// rate passed in. Margin of error is applied to the boundaries for approximation.
- bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
- return minRefreshRate.lessThanOrEqualWithMargin(getFps()) &&
- getFps().lessThanOrEqualWithMargin(maxRefreshRate);
- }
+ bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const;
- bool operator!=(const RefreshRate& other) const { return mode != other.mode; }
+ bool operator==(const RefreshRate& other) const { return mode == other.mode; }
+ bool operator!=(const RefreshRate& other) const { return !operator==(other); }
bool operator<(const RefreshRate& other) const {
- return getFps().getValue() < other.getFps().getValue();
+ return isStrictlyLess(getFps(), other.getFps());
}
- bool operator==(const RefreshRate& other) const { return !(*this != other); }
-
std::string toString() const;
friend std::ostream& operator<<(std::ostream& os, const RefreshRate& refreshRate) {
return os << refreshRate.toString();
@@ -105,11 +101,11 @@
std::unordered_map<DisplayModeId, std::unique_ptr<const RefreshRate>>;
struct FpsRange {
- Fps min{0.0f};
- Fps max{std::numeric_limits<float>::max()};
+ Fps min = Fps::fromValue(0.f);
+ Fps max = Fps::fromValue(std::numeric_limits<float>::max());
bool operator==(const FpsRange& other) const {
- return min.equalsWithMargin(other.min) && max.equalsWithMargin(other.max);
+ return isApproxEqual(min, other.min) && isApproxEqual(max, other.max);
}
bool operator!=(const FpsRange& other) const { return !(*this == other); }
@@ -221,7 +217,7 @@
// Layer vote type.
LayerVoteType vote = LayerVoteType::NoVote;
// Layer's desired refresh rate, if applicable.
- Fps desiredRefreshRate{0.0f};
+ Fps desiredRefreshRate;
// If a seamless mode switch is required.
Seamlessness seamlessness = Seamlessness::Default;
// Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer
@@ -232,7 +228,7 @@
bool operator==(const LayerRequirement& other) const {
return name == other.name && vote == other.vote &&
- desiredRefreshRate.equalsWithMargin(other.desiredRefreshRate) &&
+ isApproxEqual(desiredRefreshRate, other.desiredRefreshRate) &&
seamlessness == other.seamlessness && weight == other.weight &&
focused == other.focused;
}
@@ -247,18 +243,14 @@
// True if the system hasn't seen any buffers posted to layers recently.
bool idle = false;
- bool operator==(const GlobalSignals& other) const {
+ bool operator==(GlobalSignals other) const {
return touch == other.touch && idle == other.idle;
}
};
- // Returns the refresh rate that fits best to the given layers.
- // layers - The layer requirements to consider.
- // globalSignals - global state of touch and idle
- // outSignalsConsidered - An output param that tells the caller whether the refresh rate was
- // chosen based on touch boost and/or idle timer.
- RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>& layers,
- const GlobalSignals& globalSignals,
+ // Returns the refresh rate that best fits the given layers. outSignalsConsidered returns
+ // whether the refresh rate was chosen based on touch boost and/or idle timer.
+ RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals,
GlobalSignals* outSignalsConsidered = nullptr) const
EXCLUDES(mLock);
@@ -349,13 +341,10 @@
static bool isFractionalPairOrMultiple(Fps, Fps);
using UidToFrameRateOverride = std::map<uid_t, Fps>;
+
// Returns the frame rate override for each uid.
- //
- // @param layers list of visible layers
- // @param displayFrameRate the display frame rate
- // @param touch whether touch timer is active (i.e. user touched the screen recently)
- UidToFrameRateOverride getFrameRateOverrides(const std::vector<LayerRequirement>& layers,
- Fps displayFrameRate, bool touch) const
+ UidToFrameRateOverride getFrameRateOverrides(const std::vector<LayerRequirement>&,
+ Fps displayFrameRate, GlobalSignals) const
EXCLUDES(mLock);
bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; }
@@ -396,13 +385,12 @@
const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock);
- std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>& layers,
- const GlobalSignals& globalSignals,
+ std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>&,
+ GlobalSignals,
GlobalSignals* outSignalsConsidered) const
REQUIRES(mLock);
- RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
- const GlobalSignals& globalSignals,
+ RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>&, GlobalSignals,
GlobalSignals* outSignalsConsidered) const REQUIRES(mLock);
// Returns the refresh rate with the highest score in the collection specified from begin
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 208a767..80aa96f 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -16,15 +16,17 @@
#pragma once
+#include <chrono>
#include <numeric>
+#include <android-base/stringprintf.h>
+#include <ftl/small_map.h>
+#include <utils/Timers.h>
+
#include "Fps.h"
#include "Scheduler/SchedulerUtils.h"
#include "TimeStats/TimeStats.h"
-#include "android-base/stringprintf.h"
-#include "utils/Timers.h"
-
namespace android::scheduler {
/**
@@ -40,6 +42,7 @@
static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
public:
+ // TODO(b/185535769): Inject clock to avoid sleeping in tests.
RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate,
android::hardware::graphics::composer::hal::PowerMode currentPowerMode)
: mTimeStats(timeStats),
@@ -58,7 +61,7 @@
// Sets config mode. If the mode has changed, it records how much time was spent in the previous
// mode.
void setRefreshRate(Fps currRefreshRate) {
- if (mCurrentRefreshRate.equalsWithMargin(currRefreshRate)) {
+ if (isApproxEqual(mCurrentRefreshRate, currRefreshRate)) {
return;
}
mTimeStats.incrementRefreshRateSwitches();
@@ -66,25 +69,26 @@
mCurrentRefreshRate = currRefreshRate;
}
- // Returns a map between human readable refresh rate and number of seconds the device spent in
- // that mode.
- std::unordered_map<std::string, int64_t> getTotalTimes() {
+ // Maps stringified refresh rate to total time spent in that mode.
+ using TotalTimes = ftl::SmallMap<std::string, std::chrono::milliseconds, 3>;
+
+ TotalTimes getTotalTimes() {
// If the power mode is on, then we are probably switching between the config modes. If
// it's not then the screen is probably off. Make sure to flush times before printing
// them.
flushTime();
- std::unordered_map<std::string, int64_t> totalTime;
- // Multiple configs may map to the same name, e.g. "60fps". Add the
- // times for such configs together.
- for (const auto& [configId, time] : mConfigModesTotalTime) {
- totalTime[to_string(configId)] = 0;
+ TotalTimes totalTimes = ftl::init::map("ScreenOff", mScreenOffTime);
+ const auto zero = std::chrono::milliseconds::zero();
+
+ // Sum the times for modes that map to the same name, e.g. "60 Hz".
+ for (const auto& [fps, time] : mFpsTotalTimes) {
+ const auto string = to_string(fps);
+ const auto total = std::as_const(totalTimes).get(string).value_or(std::cref(zero));
+ totalTimes.emplace_or_replace(string, total.get() + time);
}
- for (const auto& [configId, time] : mConfigModesTotalTime) {
- totalTime[to_string(configId)] += time;
- }
- totalTime["ScreenOff"] = mScreenOffTime;
- return totalTime;
+
+ return totalTimes;
}
// Traverses through the map of config modes and returns how long they've been running in easy
@@ -102,28 +106,32 @@
// Calculates the time that passed in ms between the last time we recorded time and the time
// this method was called.
void flushTime() {
- nsecs_t currentTime = systemTime();
- nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
- int64_t timeElapsedMs = ns2ms(timeElapsed);
+ const nsecs_t currentTime = systemTime();
+ const nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
mPreviousRecordedTime = currentTime;
+ const auto duration = std::chrono::milliseconds{ns2ms(timeElapsed)};
+ const auto zero = std::chrono::milliseconds::zero();
+
uint32_t fps = 0;
+
if (mCurrentPowerMode == android::hardware::graphics::composer::hal::PowerMode::ON) {
// Normal power mode is counted under different config modes.
- if (mConfigModesTotalTime.find(mCurrentRefreshRate) == mConfigModesTotalTime.end()) {
- mConfigModesTotalTime[mCurrentRefreshRate] = 0;
- }
- mConfigModesTotalTime[mCurrentRefreshRate] += timeElapsedMs;
+ const auto total = std::as_const(mFpsTotalTimes)
+ .get(mCurrentRefreshRate)
+ .value_or(std::cref(zero));
+ mFpsTotalTimes.emplace_or_replace(mCurrentRefreshRate, total.get() + duration);
+
fps = static_cast<uint32_t>(mCurrentRefreshRate.getIntValue());
} else {
- mScreenOffTime += timeElapsedMs;
+ mScreenOffTime += duration;
}
mTimeStats.recordRefreshRate(fps, timeElapsed);
}
// Formats the time in milliseconds into easy to read format.
- static std::string getDateFormatFromMs(int64_t timeMs) {
- auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY);
+ static std::string getDateFormatFromMs(std::chrono::milliseconds time) {
+ auto [days, dayRemainderMs] = std::div(static_cast<int64_t>(time.count()), MS_PER_DAY);
auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR);
auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN);
auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S);
@@ -138,9 +146,8 @@
Fps mCurrentRefreshRate;
android::hardware::graphics::composer::hal::PowerMode mCurrentPowerMode;
- std::unordered_map<Fps, int64_t /* duration in ms */, std::hash<Fps>, Fps::EqualsInBuckets>
- mConfigModesTotalTime;
- int64_t mScreenOffTime = 0;
+ ftl::SmallMap<Fps, std::chrono::milliseconds, 2, FpsApproxEqual> mFpsTotalTimes;
+ std::chrono::milliseconds mScreenOffTime = std::chrono::milliseconds::zero();
nsecs_t mPreviousRecordedTime = systemTime();
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 8c50c16..eeea25d 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -206,14 +206,14 @@
{
const auto iter = mFrameRateOverridesFromBackdoor.find(uid);
if (iter != mFrameRateOverridesFromBackdoor.end()) {
- return std::make_optional<Fps>(iter->second);
+ return iter->second;
}
}
{
const auto iter = mFrameRateOverridesByContent.find(uid);
if (iter != mFrameRateOverridesByContent.end()) {
- return std::make_optional<Fps>(iter->second);
+ return iter->second;
}
}
@@ -699,15 +699,16 @@
return mRefreshRateConfigs->getCurrentRefreshRate();
}();
- constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER{65.0f};
- if (state == TimerState::Reset &&
- refreshRate.getFps().greaterThanWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) {
+ constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
+ using namespace fps_approx_ops;
+
+ if (state == TimerState::Reset && refreshRate.getFps() > FPS_THRESHOLD_FOR_KERNEL_TIMER) {
// If we're not in performance mode then the kernel timer shouldn't do
// anything, as the refresh rate during DPU power collapse will be the
// same.
resyncToHardwareVsync(true /* makeAvailable */, refreshRate.getVsyncPeriod());
} else if (state == TimerState::Expired &&
- refreshRate.getFps().lessThanOrEqualWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) {
+ refreshRate.getFps() <= FPS_THRESHOLD_FOR_KERNEL_TIMER) {
// Disable HW VSYNC if the timer expired, as we don't need it enabled if
// we're not pushing frames, and if we're in PERFORMANCE mode then we'll
// need to update the VsyncController model anyway.
@@ -790,13 +791,12 @@
if (!consideredSignals.idle) {
const auto frameRateOverrides =
refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements,
- displayRefreshRate,
- consideredSignals.touch);
+ displayRefreshRate, consideredSignals);
std::lock_guard lock(mFrameRateOverridesLock);
if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(),
frameRateOverrides.begin(), frameRateOverrides.end(),
- [](const std::pair<uid_t, Fps>& a, const std::pair<uid_t, Fps>& b) {
- return a.first == b.first && a.second.equalsWithMargin(b.second);
+ [](const auto& lhs, const auto& rhs) {
+ return lhs.first == rhs.first && isApproxEqual(lhs.second, rhs.second);
})) {
mFrameRateOverridesByContent = frameRateOverrides;
return true;
@@ -921,7 +921,8 @@
std::lock_guard lock(mFrameRateOverridesLock);
if (frameRateOverride.frameRateHz != 0.f) {
- mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz);
+ mFrameRateOverridesFromBackdoor[frameRateOverride.uid] =
+ Fps::fromValue(frameRateOverride.frameRateHz);
} else {
mFrameRateOverridesFromBackdoor.erase(frameRateOverride.uid);
}
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
index 43e0297..ff31651 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
@@ -48,14 +48,12 @@
}
PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRateLocked(Fps fps) const {
- const auto iter = mOffsetsCache.find(fps);
- if (iter != mOffsetsCache.end()) {
- return iter->second;
+ if (const auto offsets = mOffsetsCache.get(fps)) {
+ return offsets->get();
}
- const auto offset = constructOffsets(fps.getPeriodNsecs());
- mOffsetsCache[fps] = offset;
- return offset;
+ const auto [it, _] = mOffsetsCache.try_emplace(fps, constructOffsets(fps.getPeriodNsecs()));
+ return it->second;
}
void VsyncConfiguration::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
index 3e53b3f..8447512 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
@@ -17,10 +17,10 @@
#pragma once
#include <mutex>
-#include <type_traits>
-#include <unordered_map>
-#include <vector>
+#include <optional>
+#include <string>
+#include <ftl/small_map.h>
#include <utils/Timers.h>
#include "Fps.h"
@@ -88,9 +88,8 @@
VsyncConfigSet getConfigsForRefreshRateLocked(Fps fps) const REQUIRES(mLock);
- mutable std::unordered_map<Fps, VsyncConfigSet, std::hash<Fps>, Fps::EqualsInBuckets>
- mOffsetsCache GUARDED_BY(mLock);
- std::atomic<Fps> mRefreshRateFps GUARDED_BY(mLock);
+ mutable ftl::SmallMap<Fps, VsyncConfigSet, 2, FpsApproxEqual> mOffsetsCache GUARDED_BY(mLock);
+ Fps mRefreshRateFps GUARDED_BY(mLock);
mutable std::mutex mLock;
};
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index b2b0451..2000c54 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -25,6 +25,8 @@
#include <binder/IBinder.h>
#include <utils/Timers.h>
+#include "../WpHash.h"
+
namespace android::scheduler {
// State machine controlled by transaction flags. VsyncModulator switches to early phase offsets
@@ -124,12 +126,6 @@
using Schedule = TransactionSchedule;
std::atomic<Schedule> mTransactionSchedule = Schedule::Late;
- struct WpHash {
- size_t operator()(const wp<IBinder>& p) const {
- return std::hash<IBinder*>()(p.unsafe_get());
- }
- };
-
std::unordered_set<wp<IBinder>, WpHash> mEarlyWakeupRequests GUARDED_BY(mMutex);
std::atomic<bool> mRefreshRateChangePending = false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index af6d000..c2dcd70 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -263,14 +263,6 @@
return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
}
-class FrameRateFlexibilityToken : public BBinder {
-public:
- FrameRateFlexibilityToken(std::function<void()> callback) : mCallback(callback) {}
- virtual ~FrameRateFlexibilityToken() { mCallback(); }
-
-private:
- std::function<void()> mCallback;
-};
enum Permission {
ACCESS_SURFACE_FLINGER = 0x1,
@@ -339,9 +331,8 @@
ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
-bool SurfaceFlinger::useFrameRateApi;
bool SurfaceFlinger::enableSdrDimming;
-bool SurfaceFlinger::enableLatchUnsignaled;
+LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig;
std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
switch(displayColorSetting) {
@@ -494,14 +485,22 @@
android::hardware::details::setTrebleTestingOverride(true);
}
- useFrameRateApi = use_frame_rate_api(true);
-
mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0);
// Debug property overrides ro. property
enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false));
- enableLatchUnsignaled = base::GetBoolProperty("debug.sf.latch_unsignaled"s, false);
+ enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
+}
+
+LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
+ if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) {
+ return LatchUnsignaledConfig::Always;
+ } else if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) {
+ return LatchUnsignaledConfig::Auto;
+ } else {
+ return LatchUnsignaledConfig::Disabled;
+ }
}
SurfaceFlinger::~SurfaceFlinger() = default;
@@ -709,6 +708,7 @@
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mFlagManager = std::make_unique<android::FlagManager>();
+ mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint());
mFrameTracer->initialize();
mFrameTimeline->onBootFinished();
@@ -1039,7 +1039,7 @@
outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
const auto vsyncConfigSet =
- mVsyncConfiguration->getConfigsForRefreshRate(Fps(outMode.refreshRate));
+ mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate));
outMode.appVsyncOffset = vsyncConfigSet.late.appOffset;
outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
outMode.group = mode->getGroup();
@@ -1773,24 +1773,6 @@
*compositorTiming = getBE().mCompositorTiming;
}
-void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
- Scheduler::ModeEvent event) {
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display || mBootStage != BootStage::FINISHED) {
- return;
- }
- ATRACE_CALL();
-
- // Don't do any updating if the current fps is the same as the new one.
- if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) {
- ALOGV("Skipping mode %d as it is not part of allowed modes",
- refreshRate.getModeId().value());
- return;
- }
-
- setDesiredActiveMode({refreshRate.getMode(), event});
-}
-
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
hal::Connection connection) {
const bool connected = connection == hal::Connection::CONNECTED;
@@ -2427,7 +2409,7 @@
}
}
-void SurfaceFlinger::computeLayerBounds() {
+FloatRect SurfaceFlinger::getMaxDisplayBounds() {
// Find the largest width and height among all the displays.
int32_t maxDisplayWidth = 0;
int32_t maxDisplayHeight = 0;
@@ -2445,8 +2427,13 @@
// 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(-maxDisplayWidth * 10, -maxDisplayHeight * 10, maxDisplayWidth * 10,
- maxDisplayHeight * 10);
+ FloatRect maxBounds = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10,
+ maxDisplayWidth * 10, maxDisplayHeight * 10);
+ return maxBounds;
+}
+
+void SurfaceFlinger::computeLayerBounds() {
+ FloatRect maxBounds = getMaxDisplayBounds();
for (const auto& layer : mDrawingState.layersSortedByZ) {
layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
}
@@ -3120,7 +3107,21 @@
// Scheduler::chooseRefreshRateForContent
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
- changeRefreshRateLocked(refreshRate, event);
+
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display || mBootStage != BootStage::FINISHED) {
+ return;
+ }
+ ATRACE_CALL();
+
+ // Don't do any updating if the current fps is the same as the new one.
+ if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) {
+ ALOGV("Skipping mode %d as it is not part of allowed modes",
+ refreshRate.getModeId().value());
+ return;
+ }
+
+ setDesiredActiveMode({refreshRate.getMode(), event});
}
void SurfaceFlinger::triggerOnFrameRateOverridesChanged() {
@@ -3355,8 +3356,7 @@
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
- const sp<IBinder>& parentHandle,
- const sp<Layer>& parentLayer, bool addToRoot,
+ const wp<Layer>& parent, bool addToRoot,
uint32_t* outTransformHint) {
if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
@@ -3368,7 +3368,7 @@
if (gbc != nullptr) {
initialProducer = IInterface::asBinder(gbc);
}
- setLayerCreatedState(handle, lbc, parentHandle, parentLayer, initialProducer, addToRoot);
+ setLayerCreatedState(handle, lbc, parent, initialProducer, addToRoot);
// Create a transaction includes the initial parent and producer.
Vector<ComposerState> states;
@@ -3380,7 +3380,6 @@
states.add(composerState);
lbc->updateTransformHint(mActiveDisplayTransformHint);
-
if (outTransformHint) {
*outTransformHint = mActiveDisplayTransformHint;
}
@@ -3421,29 +3420,34 @@
}
bool SurfaceFlinger::flushTransactionQueues() {
- bool needsTraversal = false;
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
// states) around outside the scope of the lock
- std::vector<const TransactionState> transactions;
+ std::vector<TransactionState> transactions;
// Layer handles that have transactions with buffers that are ready to be applied.
std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> bufferLayersReadyToPresent;
{
Mutex::Autolock _l(mStateLock);
{
Mutex::Autolock _l(mQueueLock);
+ // allowLatchUnsignaled acts as a filter condition when latch unsignaled is either auto
+ // or always. auto: in this case we let buffer latch unsignaled if we have only one
+ // applyToken and if only first transaction is latch unsignaled. If more than one
+ // applyToken we don't latch unsignaled.
+ bool allowLatchUnsignaled = allowedLatchUnsignaled();
+ bool isFirstUnsignaledTransactionApplied = false;
// Collect transactions from pending transaction queue.
auto it = mPendingTransactionQueues.begin();
while (it != mPendingTransactionQueues.end()) {
auto& [applyToken, transactionQueue] = *it;
-
while (!transactionQueue.empty()) {
auto& transaction = transactionQueue.front();
if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
transaction.isAutoTimestamp,
transaction.desiredPresentTime,
transaction.originUid, transaction.states,
- bufferLayersReadyToPresent)) {
+ bufferLayersReadyToPresent,
+ allowLatchUnsignaled)) {
setTransactionFlags(eTransactionFlushNeeded);
break;
}
@@ -3452,6 +3456,14 @@
});
transactions.emplace_back(std::move(transaction));
transactionQueue.pop();
+ if (allowLatchUnsignaled &&
+ enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) {
+ // if allowLatchUnsignaled && we are in LatchUnsignaledConfig::Auto
+ // then we should have only one applyToken for processing.
+ // so we can stop further transactions on this applyToken.
+ isFirstUnsignaledTransactionApplied = true;
+ break;
+ }
}
if (transactionQueue.empty()) {
@@ -3463,52 +3475,115 @@
}
// Collect transactions from current transaction queue or queue to pending transactions.
- // Case 1: push to pending when transactionIsReadyToBeApplied is false.
+ // Case 1: push to pending when transactionIsReadyToBeApplied is false
+ // or the first transaction was unsignaled.
// Case 2: push to pending when there exist a pending queue.
- // Case 3: others are ready to apply.
+ // Case 3: others are the transactions that are ready to apply.
while (!mTransactionQueue.empty()) {
auto& transaction = mTransactionQueue.front();
bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) !=
mPendingTransactionQueues.end();
- if (pendingTransactions ||
+ if (isFirstUnsignaledTransactionApplied || pendingTransactions ||
!transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
transaction.isAutoTimestamp,
transaction.desiredPresentTime,
transaction.originUid, transaction.states,
- bufferLayersReadyToPresent)) {
+ bufferLayersReadyToPresent,
+ allowLatchUnsignaled)) {
mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
} else {
transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
bufferLayersReadyToPresent.insert(state.surface);
});
transactions.emplace_back(std::move(transaction));
+ if (allowLatchUnsignaled &&
+ enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) {
+ isFirstUnsignaledTransactionApplied = true;
+ }
}
- mTransactionQueue.pop();
+ mTransactionQueue.pop_front();
ATRACE_INT("TransactionQueue", mTransactionQueue.size());
}
- }
- // Now apply all transactions.
- for (const auto& transaction : transactions) {
- needsTraversal |=
- applyTransactionState(transaction.frameTimelineInfo, transaction.states,
- transaction.displays, transaction.flags,
- transaction.inputWindowCommands,
- transaction.desiredPresentTime,
- transaction.isAutoTimestamp, transaction.buffer,
- transaction.postTime, transaction.permissions,
- transaction.hasListenerCallbacks,
- transaction.listenerCallbacks, transaction.originPid,
- transaction.originUid, transaction.id);
- if (transaction.transactionCommittedSignal) {
- mTransactionCommittedSignals.emplace_back(
- std::move(transaction.transactionCommittedSignal));
- }
+ return applyTransactions(transactions);
}
- } // unlock mStateLock
+ }
+}
+
+bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) {
+ bool needsTraversal = false;
+ // Now apply all transactions.
+ for (const auto& transaction : transactions) {
+ needsTraversal |=
+ applyTransactionState(transaction.frameTimelineInfo, transaction.states,
+ transaction.displays, transaction.flags,
+ transaction.inputWindowCommands,
+ transaction.desiredPresentTime, transaction.isAutoTimestamp,
+ transaction.buffer, transaction.postTime,
+ transaction.permissions, transaction.hasListenerCallbacks,
+ transaction.listenerCallbacks, transaction.originPid,
+ transaction.originUid, transaction.id);
+ if (transaction.transactionCommittedSignal) {
+ mTransactionCommittedSignals.emplace_back(
+ std::move(transaction.transactionCommittedSignal));
+ }
+ }
return needsTraversal;
}
+bool SurfaceFlinger::allowedLatchUnsignaled() {
+ if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
+ return false;
+ }
+ // Always mode matches the current latch unsignaled behavior.
+ // This behavior is currently used by the partners and we would like
+ // to keep it until we are completely migrated to Auto mode successfully
+ // and we we have our fallback based implementation in place.
+ if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) {
+ return true;
+ }
+
+ // if enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto
+ // we don't latch unsignaled if more than one applyToken, as it can backpressure
+ // the other transactions.
+ if (mPendingTransactionQueues.size() > 1) {
+ return false;
+ }
+ std::optional<sp<IBinder>> applyToken = std::nullopt;
+ bool isPendingTransactionQueuesItem = false;
+ if (!mPendingTransactionQueues.empty()) {
+ applyToken = mPendingTransactionQueues.begin()->first;
+ isPendingTransactionQueuesItem = true;
+ }
+
+ for (const auto& item : mTransactionQueue) {
+ if (!applyToken.has_value()) {
+ applyToken = item.applyToken;
+ } else if (applyToken.has_value() && applyToken != item.applyToken) {
+ return false;
+ }
+ }
+
+ if (isPendingTransactionQueuesItem) {
+ return checkTransactionCanLatchUnsignaled(
+ mPendingTransactionQueues.begin()->second.front());
+ } else if (applyToken.has_value()) {
+ return checkTransactionCanLatchUnsignaled((mTransactionQueue.front()));
+ }
+ return false;
+}
+
+bool SurfaceFlinger::checkTransactionCanLatchUnsignaled(const TransactionState& transaction) {
+ if (transaction.states.size() == 1) {
+ const auto& state = transaction.states.begin()->state;
+ return (state.flags & ~layer_state_t::eBufferChanged) == 0 &&
+ state.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) &&
+ state.bufferData.acquireFence &&
+ state.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled;
+ }
+ return false;
+}
+
bool SurfaceFlinger::transactionFlushNeeded() {
Mutex::Autolock _l(mQueueLock);
return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty();
@@ -3540,7 +3615,8 @@
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>&
- bufferLayersReadyToPresent) const {
+ bufferLayersReadyToPresent,
+ bool allowLatchUnsignaled) const {
ATRACE_CALL();
const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
@@ -3567,7 +3643,7 @@
const layer_state_t& s = state.state;
const bool acquireFenceChanged =
s.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged);
- if (acquireFenceChanged && s.bufferData.acquireFence && !enableLatchUnsignaled &&
+ if (acquireFenceChanged && s.bufferData.acquireFence && !allowLatchUnsignaled &&
s.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled) {
ATRACE_NAME("fence unsignaled");
return false;
@@ -3628,7 +3704,7 @@
: CountDownLatch::eSyncTransaction));
}
- mTransactionQueue.emplace(state);
+ mTransactionQueue.emplace_back(state);
ATRACE_INT("TransactionQueue", mTransactionQueue.size());
const auto schedule = [](uint32_t flags) {
@@ -3920,7 +3996,7 @@
}
if (what & layer_state_t::eLayerChanged) {
// NOTE: index needs to be calculated before we update the state
- auto p = layer->getParent();
+ const auto& p = layer->getParent();
if (p == nullptr) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
if (layer->setLayer(s.z) && idx >= 0) {
@@ -3938,7 +4014,7 @@
}
if (what & layer_state_t::eRelativeLayerChanged) {
// NOTE: index needs to be calculated before we update the state
- auto p = layer->getParent();
+ const auto& p = layer->getParent();
const auto& relativeHandle = s.relativeLayerSurfaceControl ?
s.relativeLayerSurfaceControl->getHandle() : nullptr;
if (p == nullptr) {
@@ -4108,7 +4184,8 @@
const auto strategy =
Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy);
- if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) {
+ if (layer->setFrameRate(
+ Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) {
flags |= eTraversalNeeded;
}
}
@@ -4204,7 +4281,7 @@
sp<Layer> mirrorLayer;
sp<Layer> mirrorFrom;
- std::string uniqueName = getUniqueLayerName("MirrorRoot");
+ std::string layerName = "MirrorRoot";
{
Mutex::Autolock _l(mStateLock);
@@ -4213,7 +4290,7 @@
return NAME_NOT_FOUND;
}
- status_t result = createContainerLayer(client, std::move(uniqueName), -1, -1, 0,
+ status_t result = createContainerLayer(client, std::move(layerName), -1, -1, 0,
LayerMetadata(), outHandle, &mirrorLayer);
if (result != NO_ERROR) {
return result;
@@ -4223,7 +4300,7 @@
}
*outLayerId = mirrorLayer->sequence;
- return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false,
+ return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, false,
nullptr /* outTransformHint */);
}
@@ -4247,12 +4324,12 @@
sp<Layer> layer;
- std::string uniqueName = getUniqueLayerName(name.string());
+ std::string layerName{name.string()};
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
case ISurfaceComposerClient::eFXSurfaceBufferState: {
- result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
+ result = createBufferStateLayer(client, std::move(layerName), w, h, flags,
std::move(metadata), handle, &layer);
std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter();
if (pendingBufferCounter) {
@@ -4269,7 +4346,7 @@
return BAD_VALUE;
}
- result = createEffectLayer(client, std::move(uniqueName), w, h, flags,
+ result = createEffectLayer(client, std::move(layerName), w, h, flags,
std::move(metadata), handle, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceContainer:
@@ -4279,7 +4356,7 @@
int(w), int(h));
return BAD_VALUE;
}
- result = createContainerLayer(client, std::move(uniqueName), w, h, flags,
+ result = createContainerLayer(client, std::move(layerName), w, h, flags,
std::move(metadata), handle, &layer);
break;
default:
@@ -4292,43 +4369,24 @@
}
bool addToRoot = callingThreadHasUnscopedSurfaceFlingerAccess();
- result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, addToRoot,
- outTransformHint);
+ wp<Layer> parent(parentHandle != nullptr ? fromHandle(parentHandle) : parentLayer);
+ if (parentHandle != nullptr && parent == nullptr) {
+ ALOGE("Invalid parent handle %p.", parentHandle.get());
+ addToRoot = false;
+ }
+ if (parentLayer != nullptr) {
+ addToRoot = false;
+ }
+ result = addClientLayer(client, *handle, *gbp, layer, parent, addToRoot, outTransformHint);
if (result != NO_ERROR) {
return result;
}
- mInterceptor->saveSurfaceCreation(layer);
setTransactionFlags(eTransactionNeeded);
*outLayerId = layer->sequence;
return result;
}
-std::string SurfaceFlinger::getUniqueLayerName(const char* name) {
- unsigned dupeCounter = 0;
-
- // Tack on our counter whether there is a hit or not, so everyone gets a tag
- std::string uniqueName = base::StringPrintf("%s#%u", name, dupeCounter);
-
- // Grab the state lock since we're accessing mCurrentState
- Mutex::Autolock lock(mStateLock);
-
- // Loop over layers until we're sure there is no matching name
- bool matchFound = true;
- while (matchFound) {
- matchFound = false;
- mCurrentState.traverse([&](Layer* layer) {
- if (layer->getName() == uniqueName) {
- matchFound = true;
- uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter);
- }
- });
- }
-
- ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name, uniqueName.c_str());
- return uniqueName;
-}
-
status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::string name,
uint32_t w, uint32_t h, uint32_t flags,
LayerMetadata metadata, PixelFormat& format,
@@ -5176,11 +5234,9 @@
case SET_GLOBAL_SHADOW_SETTINGS:
case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
- // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests,
- // which acquire the necessary permission dynamically. Don't use the permission cache
- // for this check.
- bool usePermissionCache =
- code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN && code != OVERRIDE_HDR_TYPES;
+ // OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary
+ // permission dynamically. Don't use the permission cache for this check.
+ bool usePermissionCache = code != OVERRIDE_HDR_TYPES;
if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
IPCThreadState* ipc = IPCThreadState::self();
ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
@@ -5632,17 +5688,39 @@
mDebugDisplayModeSetByBackdoor = result == NO_ERROR;
return result;
}
+ // Turn on/off frame rate flexibility mode. When turned on it overrides the display
+ // manager frame rate policy a new policy which allows switching between all refresh
+ // rates.
case 1036: {
- if (data.readInt32() > 0) {
- status_t result =
- acquireFrameRateFlexibilityToken(&mDebugFrameRateFlexibilityToken);
- if (result != NO_ERROR) {
- return result;
- }
- } else {
- mDebugFrameRateFlexibilityToken = nullptr;
+ if (data.readInt32() > 0) { // turn on
+ return schedule([this] {
+ const auto display = ON_MAIN_THREAD(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 be
+ // setting a new display manager policy, leaving us using a stale
+ // defaultMode. The defaultMode doesn't matter for the override
+ // policy though, since we set allowGroupSwitching to true, so it's
+ // not a problem.
+ scheduler::RefreshRateConfigs::Policy overridePolicy;
+ overridePolicy.defaultMode = display->refreshRateConfigs()
+ .getDisplayManagerPolicy()
+ .defaultMode;
+ overridePolicy.allowGroupSwitching = true;
+ constexpr bool kOverridePolicy = true;
+ return setDesiredDisplayModeSpecsInternal(display, overridePolicy,
+ kOverridePolicy);
+ })
+ .get();
+ } else { // turn off
+ return schedule([this] {
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ constexpr bool kOverridePolicy = true;
+ return setDesiredDisplayModeSpecsInternal(display, {},
+ kOverridePolicy);
+ })
+ .get();
}
- return NO_ERROR;
}
// Inject a hotplug connected event for the primary display. This will deallocate and
// reallocate the display state including framebuffers.
@@ -6000,9 +6078,7 @@
sp<Layer> parent;
Rect crop(args.sourceCrop);
std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
- Rect layerStackSpaceRect;
ui::Dataspace dataspace;
- bool captureSecureLayers;
// Call this before holding mStateLock to avoid any deadlocking.
bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
@@ -6011,7 +6087,7 @@
Mutex::Autolock lock(mStateLock);
parent = fromHandle(args.layerHandle).promote();
- if (parent == nullptr || parent->isRemovedFromCurrentState()) {
+ if (parent == nullptr) {
ALOGE("captureLayers called with an invalid or removed parent");
return NAME_NOT_FOUND;
}
@@ -6050,43 +6126,38 @@
}
}
- const auto display =
- findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
- return display.getLayerStack() == layerStack;
- });
-
- if (!display) {
- return NAME_NOT_FOUND;
- }
-
- layerStackSpaceRect = display->getLayerStackSpaceRect();
-
// The dataspace is depended on the color mode of display, that could use non-native mode
// (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes,
// and failed if display is not in native mode. This provide a way to force using native
// colors when capture.
dataspace = args.dataspace;
if (dataspace == ui::Dataspace::UNKNOWN) {
+ auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
+ return display.getLayerStack() == layerStack;
+ });
+ if (!display) {
+ // If the layer is not on a display, use the dataspace for the default display.
+ display = getDefaultDisplayDeviceLocked();
+ }
+
const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
dataspace = pickDataspaceFromColorMode(colorMode);
}
- captureSecureLayers = args.captureSecureLayers && display->isSecure();
} // mStateLock
// really small crop or frameScale
- if (reqSize.width <= 0) {
- reqSize.width = 1;
- }
- if (reqSize.height <= 0) {
- reqSize.height = 1;
+ if (reqSize.width <= 0 || reqSize.height <= 0) {
+ ALOGW("Failed to captureLayes: crop or scale too small");
+ return BAD_VALUE;
}
+ Rect layerStackSpaceRect(0, 0, reqSize.width, reqSize.height);
bool childrenOnly = args.childrenOnly;
RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> {
return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
childrenOnly, layerStackSpaceRect,
- captureSecureLayers);
+ args.captureSecureLayers);
});
auto traverseLayers = [parent, args, excludeLayers](const LayerVector::Visitor& visitor) {
@@ -6099,7 +6170,7 @@
return;
}
- auto p = layer;
+ sp<Layer> p = layer;
while (p != nullptr) {
if (excludeLayers.count(p) != 0) {
return;
@@ -6488,8 +6559,10 @@
using Policy = scheduler::RefreshRateConfigs::Policy;
const Policy policy{DisplayModeId(defaultMode),
allowGroupSwitching,
- {Fps(primaryRefreshRateMin), Fps(primaryRefreshRateMax)},
- {Fps(appRequestRefreshRateMin), Fps(appRequestRefreshRateMax)}};
+ {Fps::fromValue(primaryRefreshRateMin),
+ Fps::fromValue(primaryRefreshRateMax)},
+ {Fps::fromValue(appRequestRefreshRateMin),
+ Fps::fromValue(appRequestRefreshRateMax)}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
@@ -6621,7 +6694,7 @@
const auto strategy =
Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy);
if (layer->setFrameRate(
- Layer::FrameRate(Fps{frameRate},
+ Layer::FrameRate(Fps::fromValue(frameRate),
Layer::FrameRate::convertCompatibility(compatibility),
strategy))) {
setTransactionFlags(eTraversalNeeded);
@@ -6636,74 +6709,6 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) {
- if (!outToken) {
- return BAD_VALUE;
- }
-
- auto future = schedule([this] {
- status_t result = NO_ERROR;
- sp<IBinder> token;
-
- if (mFrameRateFlexibilityTokenCount == 0) {
- const auto display = ON_MAIN_THREAD(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 be setting a new display
- // manager policy, leaving us using a stale defaultMode. The defaultMode doesn't
- // matter for the override policy though, since we set allowGroupSwitching to
- // true, so it's not a problem.
- scheduler::RefreshRateConfigs::Policy overridePolicy;
- overridePolicy.defaultMode =
- display->refreshRateConfigs().getDisplayManagerPolicy().defaultMode;
- overridePolicy.allowGroupSwitching = true;
- constexpr bool kOverridePolicy = true;
- result = setDesiredDisplayModeSpecsInternal(display, overridePolicy, kOverridePolicy);
- }
-
- if (result == NO_ERROR) {
- mFrameRateFlexibilityTokenCount++;
- // Handing out a reference to the SurfaceFlinger object, as we're doing in the line
- // below, is something to consider carefully. The lifetime of the
- // FrameRateFlexibilityToken isn't tied to SurfaceFlinger object lifetime, so if this
- // SurfaceFlinger object were to be destroyed while the token still exists, the token
- // destructor would be accessing a stale SurfaceFlinger reference, and crash. This is ok
- // in this case, for two reasons:
- // 1. Once SurfaceFlinger::run() is called by main_surfaceflinger.cpp, the only way
- // the program exits is via a crash. So we won't have a situation where the
- // SurfaceFlinger object is dead but the process is still up.
- // 2. The frame rate flexibility token is acquired/released only by CTS tests, so even
- // if condition 1 were changed, the problem would only show up when running CTS tests,
- // not on end user devices, so we could spot it and fix it without serious impact.
- token = new FrameRateFlexibilityToken(
- [this]() { onFrameRateFlexibilityTokenReleased(); });
- ALOGD("Frame rate flexibility token acquired. count=%d",
- mFrameRateFlexibilityTokenCount);
- }
-
- return std::make_pair(result, token);
- });
-
- status_t result;
- std::tie(result, *outToken) = future.get();
- return result;
-}
-
-void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() {
- static_cast<void>(schedule([this] {
- LOG_ALWAYS_FATAL_IF(mFrameRateFlexibilityTokenCount == 0,
- "Failed tracking frame rate flexibility tokens");
- mFrameRateFlexibilityTokenCount--;
- ALOGD("Frame rate flexibility token released. count=%d", mFrameRateFlexibilityTokenCount);
- if (mFrameRateFlexibilityTokenCount == 0) {
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
- constexpr bool kOverridePolicy = true;
- status_t result = setDesiredDisplayModeSpecsInternal(display, {}, kOverridePolicy);
- LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token");
- }
- }));
-}
-
status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
const FrameTimelineInfo& frameTimelineInfo) {
Mutex::Autolock lock(mStateLock);
@@ -6755,7 +6760,7 @@
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
- Fps maxRefreshRate(60.f);
+ Fps maxRefreshRate = 60_Hz;
if (!getHwComposer().isHeadless()) {
if (const auto display = getDefaultDisplayDevice()) {
@@ -6768,7 +6773,7 @@
}
uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const {
- Fps refreshRate(60.f);
+ Fps refreshRate = 60_Hz;
if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) {
refreshRate = *frameRateOverride;
@@ -6797,11 +6802,11 @@
}
void SurfaceFlinger::setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
- const wp<IBinder>& parent, const wp<Layer> parentLayer,
- const wp<IBinder>& producer, bool addToRoot) {
+ const wp<Layer> parent, const wp<IBinder>& producer,
+ bool addToRoot) {
Mutex::Autolock lock(mCreatedLayersLock);
mCreatedLayers[handle->localBinder()] =
- std::make_unique<LayerCreatedState>(layer, parent, parentLayer, producer, addToRoot);
+ std::make_unique<LayerCreatedState>(layer, parent, producer, addToRoot);
}
auto SurfaceFlinger::getLayerCreatedState(const sp<IBinder>& handle) {
@@ -6839,19 +6844,16 @@
}
sp<Layer> parent;
- bool allowAddRoot = state->addToRoot;
+ bool addToRoot = state->addToRoot;
if (state->initialParent != nullptr) {
- parent = fromHandle(state->initialParent.promote()).promote();
+ parent = state->initialParent.promote();
if (parent == nullptr) {
ALOGE("Invalid parent %p", state->initialParent.unsafe_get());
- allowAddRoot = false;
+ addToRoot = false;
}
- } else if (state->initialParentLayer != nullptr) {
- parent = state->initialParentLayer.promote();
- allowAddRoot = false;
}
- if (parent == nullptr && allowAddRoot) {
+ if (parent == nullptr && addToRoot) {
layer->setIsAtRoot(true);
mCurrentState.layersSortedByZ.add(layer);
} else if (parent == nullptr) {
@@ -6878,6 +6880,7 @@
}
}
+ mInterceptor->saveSurfaceCreation(layer);
return layer;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c712061..bf628dc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -135,6 +135,8 @@
eTransactionMask = 0x1f,
};
+enum class LatchUnsignaledConfig { Always, Auto, Disabled };
+
using DisplayColorSetting = compositionengine::OutputColorSetting;
struct SurfaceFlingerBE {
@@ -246,18 +248,13 @@
static ui::Dataspace wideColorGamutCompositionDataspace;
static ui::PixelFormat wideColorGamutCompositionPixelFormat;
- // Whether to use frame rate API when deciding about the refresh rate of the display. This
- // variable is caches in SF, so that we can check it with each layer creation, and a void the
- // overhead that is caused by reading from sysprop.
- static bool useFrameRateApi;
-
static constexpr SkipInitializationTag SkipInitialization;
// Whether or not SDR layers should be dimmed to the desired SDR white point instead of
// being treated as native display brightness
static bool enableSdrDimming;
- static bool enableLatchUnsignaled;
+ static LatchUnsignaledConfig enableLatchUnsignaledConfig;
// must be called before clients can connect
void init() ANDROID_API;
@@ -326,6 +323,7 @@
// Disables expensive rendering for all displays
// This is scheduled on the main thread
void disableExpensiveRendering();
+ FloatRect getMaxDisplayBounds();
protected:
// We're reference counted, never destroy SurfaceFlinger directly
@@ -601,7 +599,6 @@
float lightPosY, float lightPosZ, float lightRadius) override;
status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) override;
- status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override;
status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
const FrameTimelineInfo& frameTimelineInfo) override;
@@ -649,7 +646,7 @@
// Toggles hardware VSYNC by calling into HWC.
void setVsyncEnabled(bool) override;
- // Initiates a refresh rate change to be applied on invalidate.
+ // Initiates a refresh rate change to be applied on commit.
void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override;
// Called when kernel idle timer has expired. Used to update the refresh rate overlay.
void kernelTimerChanged(bool expired) override;
@@ -751,7 +748,14 @@
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>&
- bufferLayersReadyToPresent) const REQUIRES(mStateLock);
+ bufferLayersReadyToPresent,
+ bool allowLatchUnsignaled) const REQUIRES(mStateLock);
+ static LatchUnsignaledConfig getLatchUnsignaledConfig();
+ bool latchUnsignaledIsAllowed(std::vector<TransactionState>& transactions) REQUIRES(mStateLock);
+ bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock);
+ bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction)
+ REQUIRES(mStateLock);
+ bool applyTransactions(std::vector<TransactionState>& transactions) REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
REQUIRES(mStateLock);
@@ -786,8 +790,6 @@
status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
sp<IBinder>* outHandle, int32_t* outLayerId);
- std::string getUniqueLayerName(const char* name);
-
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
// resources associated to this layer.
@@ -797,8 +799,8 @@
// add a layer to SurfaceFlinger
status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
- const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,
- bool addToRoot, uint32_t* outTransformHint);
+ const wp<Layer>& parentLayer, bool addToRoot,
+ uint32_t* outTransformHint);
// Traverse through all the layers and compute and cache its bounds.
void computeLayerBounds();
@@ -954,10 +956,6 @@
getHwComposer().setVsyncEnabled(id, enabled);
}
- // Sets the refresh rate by switching active configs, if they are available for
- // the desired refresh rate.
- void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock);
-
struct FenceWithFenceTime {
sp<Fence> fence = Fence::NO_FENCE;
std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE;
@@ -1069,8 +1067,6 @@
return doDump(fd, args, asProto);
}
- void onFrameRateFlexibilityTokenReleased();
-
static mat4 calculateColorMatrix(float saturation);
void updateColorMatrixLocked();
@@ -1244,7 +1240,7 @@
Condition mTransactionQueueCV;
std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
mPendingTransactionQueues GUARDED_BY(mQueueLock);
- std::queue<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
+ std::deque<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
/*
* Feature prototyping
*/
@@ -1337,28 +1333,22 @@
// be any issues with a raw pointer referencing an invalid object.
std::unordered_set<Layer*> mOffscreenLayers;
- int mFrameRateFlexibilityTokenCount = 0;
-
- sp<IBinder> mDebugFrameRateFlexibilityToken;
-
BufferCountTracker mBufferCountTracker;
std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners
GUARDED_BY(mStateLock);
mutable Mutex mCreatedLayersLock;
struct LayerCreatedState {
- LayerCreatedState(const wp<Layer>& layer, const wp<IBinder>& parent,
- const wp<Layer> parentLayer, const wp<IBinder>& producer, bool addToRoot)
+ LayerCreatedState(const wp<Layer>& layer, const wp<Layer> parent,
+ const wp<IBinder>& producer, bool addToRoot)
: layer(layer),
initialParent(parent),
- initialParentLayer(parentLayer),
initialProducer(producer),
addToRoot(addToRoot) {}
wp<Layer> layer;
// Indicates the initial parent of the created layer, only used for creating layer in
// SurfaceFlinger. If nullptr, it may add the created layer into the current root layers.
- wp<IBinder> initialParent;
- wp<Layer> initialParentLayer;
+ wp<Layer> initialParent;
// Indicates the initial graphic buffer producer of the created layer, only used for
// creating layer in SurfaceFlinger.
wp<IBinder> initialProducer;
@@ -1372,8 +1362,7 @@
// thread.
std::unordered_map<BBinder*, std::unique_ptr<LayerCreatedState>> mCreatedLayers;
void setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
- const wp<IBinder>& parent, const wp<Layer> parentLayer,
- const wp<IBinder>& producer, bool addToRoot);
+ const wp<Layer> parent, const wp<IBinder>& producer, bool addToRoot);
auto getLayerCreatedState(const sp<IBinder>& handle);
sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index a8117f7..16f6e31 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -304,14 +304,6 @@
return defaultValue;
}
-bool use_frame_rate_api(bool defaultValue) {
- auto temp = SurfaceFlingerProperties::use_frame_rate_api();
- if (temp.has_value()) {
- return *temp;
- }
- return defaultValue;
-}
-
bool enable_sdr_dimming(bool defaultValue) {
return SurfaceFlingerProperties::enable_sdr_dimming().value_or(defaultValue);
}
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index ed18260..8d0e426 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -88,8 +88,6 @@
bool support_kernel_idle_timer(bool defaultValue);
-bool use_frame_rate_api(bool defaultValue);
-
int32_t display_update_imminent_timeout_ms(int32_t defaultValue);
android::ui::DisplayPrimaries getDisplayNativePrimaries();
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index cea1a33..97adb20 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -77,7 +77,7 @@
private:
class Runner;
- static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB;
+ static constexpr auto DEFAULT_BUFFER_SIZE = 20_MB;
static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope";
SurfaceFlinger& mFlinger;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 9e70684..bdeaeb8 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -129,13 +129,15 @@
nsecs_t displayPresentJitter = 0;
nsecs_t appDeadlineDelta = 0;
+ static bool isOptApproxEqual(std::optional<Fps> lhs, std::optional<Fps> rhs) {
+ return (!lhs && !rhs) || (lhs && rhs && isApproxEqual(*lhs, *rhs));
+ }
+
bool operator==(const JankyFramesInfo& o) const {
- return Fps::EqualsInBuckets{}(refreshRate, o.refreshRate) &&
- ((renderRate == std::nullopt && o.renderRate == std::nullopt) ||
- (renderRate != std::nullopt && o.renderRate != std::nullopt &&
- Fps::EqualsInBuckets{}(*renderRate, *o.renderRate))) &&
- uid == o.uid && layerName == o.layerName && gameMode == o.gameMode &&
- reasons == o.reasons && displayDeadlineDelta == o.displayDeadlineDelta &&
+ return isApproxEqual(refreshRate, o.refreshRate) &&
+ isOptApproxEqual(renderRate, o.renderRate) && uid == o.uid &&
+ layerName == o.layerName && gameMode == o.gameMode && reasons == o.reasons &&
+ displayDeadlineDelta == o.displayDeadlineDelta &&
displayPresentJitter == o.displayPresentJitter &&
appDeadlineDelta == o.appDeadlineDelta;
}
diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.h b/services/surfaceflinger/TunnelModeEnabledReporter.h
index 935502a..802d22d 100644
--- a/services/surfaceflinger/TunnelModeEnabledReporter.h
+++ b/services/surfaceflinger/TunnelModeEnabledReporter.h
@@ -22,6 +22,8 @@
#include <unordered_map>
+#include "WpHash.h"
+
namespace android {
class Layer;
@@ -54,11 +56,6 @@
private:
mutable std::mutex mMutex;
- struct WpHash {
- size_t operator()(const wp<IBinder>& p) const {
- return std::hash<IBinder*>()(p.unsafe_get());
- }
- };
std::unordered_map<wp<IBinder>, sp<gui::ITunnelModeEnabledListener>, WpHash> mListeners
GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index ecd797a..4e08393 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -23,6 +23,8 @@
#include <utils/Mutex.h>
#include <unordered_map>
+#include "WpHash.h"
+
namespace android {
class SurfaceFlinger;
@@ -42,12 +44,6 @@
private:
void windowInfosReported();
- struct WpHash {
- size_t operator()(const wp<IBinder>& p) const {
- return std::hash<IBinder*>()(p.unsafe_get());
- }
- };
-
const sp<SurfaceFlinger> mSf;
std::mutex mListenersMutex;
std::unordered_map<wp<IBinder>, const sp<gui::IWindowInfosListener>, WpHash>
diff --git a/services/surfaceflinger/WpHash.h b/services/surfaceflinger/WpHash.h
new file mode 100644
index 0000000..86777b7
--- /dev/null
+++ b/services/surfaceflinger/WpHash.h
@@ -0,0 +1,25 @@
+/*
+ * 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
+
+namespace android {
+
+struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const { return std::hash<IBinder*>()(p.unsafe_get()); }
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 673239d..caeff4a 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -63,18 +63,17 @@
return OK;
}
-static status_t startDisplayService() {
+static void startDisplayService() {
using android::frameworks::displayservice::V1_0::implementation::DisplayService;
using android::frameworks::displayservice::V1_0::IDisplayService;
sp<IDisplayService> displayservice = new DisplayService();
status_t err = displayservice->registerAsService();
+ // b/141930622
if (err != OK) {
- ALOGE("Could not register IDisplayService service.");
+ ALOGE("Did not register (deprecated) IDisplayService service.");
}
-
- return err;
}
int main(int, char**) {
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 78f8a2f..7702ea2 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -414,16 +414,6 @@
prop_name: "ro.surface_flinger.supports_background_blur"
}
-# Indicates whether Scheduler should use frame rate API when adjusting the
-# display refresh rate.
-prop {
- api_name: "use_frame_rate_api"
- type: Boolean
- scope: Public
- access: Readonly
- prop_name: "ro.surface_flinger.use_frame_rate_api"
-}
-
# Sets the timeout used to rate limit DISPLAY_UPDATE_IMMINENT Power HAL notifications.
# SurfaceFlinger wakeups will trigger this boost whenever they are separated by more than this
# duration (specified in milliseconds). A value of 0 disables the rate limit, and will result in
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 9c567d6..bf1e7e2 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -152,10 +152,6 @@
prop_name: "ro.surface_flinger.use_context_priority"
}
prop {
- api_name: "use_frame_rate_api"
- prop_name: "ro.surface_flinger.use_frame_rate_api"
- }
- prop {
api_name: "use_smart_90_for_video"
prop_name: "ro.surface_flinger.use_smart_90_for_video"
deprecated: true
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
index ba60a7d..640b9fb 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
@@ -136,10 +136,6 @@
prop_name: "ro.surface_flinger.use_context_priority"
}
prop {
- api_name: "use_frame_rate_api"
- prop_name: "ro.surface_flinger.use_frame_rate_api"
- }
- prop {
api_name: "use_smart_90_for_video"
prop_name: "ro.surface_flinger.use_smart_90_for_video"
deprecated: true
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 9cf7c09..d192a2d 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -52,17 +52,6 @@
}
};
-TEST_F(InvalidHandleTest, createSurfaceInvalidParentHandle) {
- // The createSurface is scheduled now, we could still get a created surface from createSurface.
- // Should verify if it actually added into current state by checking the screenshot.
- auto notSc = mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0,
- mNotSc->getHandle());
- LayerCaptureArgs args;
- args.layerHandle = notSc->getHandle();
- ScreenCaptureResults captureResults;
- ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
-}
-
TEST_F(InvalidHandleTest, captureLayersInvalidHandle) {
LayerCaptureArgs args;
args.layerHandle = mNotSc->getHandle();
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index 3ec6da9..a921aa8 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -273,6 +273,61 @@
}
}
+// Test that a mirror layer can be screenshot when offscreen
+TEST_F(MirrorLayerTest, OffscreenMirrorScreenshot) {
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ui::DisplayMode mode;
+ SurfaceComposerClient::getActiveDisplayMode(display, &mode);
+ const ui::Size& size = mode.resolution;
+
+ sp<SurfaceControl> grandchild =
+ createLayer("Grandchild layer", 50, 50, ISurfaceComposerClient::eFXSurfaceBufferState,
+ mChildLayer.get());
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(grandchild, Color::BLUE, 50, 50));
+ Rect childBounds = Rect(50, 50, 450, 450);
+
+ asTransaction([&](Transaction& t) {
+ t.setCrop(grandchild, Rect(0, 0, 50, 50)).show(grandchild);
+ t.setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ });
+
+ sp<SurfaceControl> mirrorLayer = nullptr;
+ {
+ // Run as system to get the ACCESS_SURFACE_FLINGER permission when mirroring
+ UIDFaker f(AID_SYSTEM);
+ // Mirror mChildLayer
+ mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ ASSERT_NE(mirrorLayer, nullptr);
+ }
+
+ // Show the mirror layer, but don't reparent to a layer on screen.
+ Transaction().show(mirrorLayer).apply();
+
+ {
+ SCOPED_TRACE("Offscreen Mirror");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, size.getWidth(), 50), Color::RED);
+ shot->expectColor(Rect(0, 0, 50, size.getHeight()), Color::RED);
+ shot->expectColor(Rect(450, 0, size.getWidth(), size.getHeight()), Color::RED);
+ shot->expectColor(Rect(0, 450, size.getWidth(), size.getHeight()), Color::RED);
+ shot->expectColor(Rect(100, 100, 450, 450), Color::GREEN);
+ shot->expectColor(Rect(50, 50, 100, 100), Color::BLUE);
+ }
+
+ {
+ SCOPED_TRACE("Capture Mirror");
+ // Capture just the mirror layer and child.
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mirrorLayer->getHandle();
+ captureArgs.sourceCrop = childBounds;
+ std::unique_ptr<ScreenCapture> shot;
+ ScreenCapture::captureLayers(&shot, captureArgs);
+ shot->expectSize(childBounds.width(), childBounds.height());
+ shot->expectColor(Rect(0, 0, 50, 50), Color::BLUE);
+ shot->expectColor(Rect(50, 50, 400, 400), Color::GREEN);
+ }
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 95301b3..f9b3185 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -37,6 +37,8 @@
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
const ui::Size& resolution = mode.resolution;
+ mDisplaySize = resolution;
+
// Background surface
mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
resolution.getHeight(), 0);
@@ -72,6 +74,7 @@
sp<SurfaceControl> mBGSurfaceControl;
sp<SurfaceControl> mFGSurfaceControl;
std::unique_ptr<ScreenCapture> mCapture;
+ ui::Size mDisplaySize;
};
TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) {
@@ -515,18 +518,8 @@
}
TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
- ISurfaceComposerClient::eFXSurfaceBufferState);
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
-
- auto redLayerHandle = redLayer->getHandle();
- Transaction().reparent(redLayer, nullptr).apply();
- redLayer.clear();
- SurfaceComposerClient::Transaction().apply(true);
-
LayerCaptureArgs args;
- args.layerHandle = redLayerHandle;
+ args.layerHandle = new BBinder();
ScreenCaptureResults captureResults;
// Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
@@ -840,6 +833,33 @@
Color{expectedColor, expectedColor, expectedColor, 255}, tolerance);
}
+TEST_F(ScreenCaptureTest, CaptureOffscreen) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().show(layer).hide(mFGSurfaceControl).reparent(layer, nullptr).apply();
+
+ DisplayCaptureArgs displayCaptureArgs;
+ displayCaptureArgs.displayToken = mDisplay;
+
+ {
+ // Validate that the red layer is not on screen
+ ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs);
+ mCapture->expectColor(Rect(0, 0, mDisplaySize.width, mDisplaySize.height),
+ {63, 63, 195, 255});
+ }
+
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = layer->getHandle();
+
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectSize(32, 32);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
// In the following tests we verify successful skipping of a parent layer,
// so we use the same verification logic and only change how we mutate
// the parent layer to verify that various properties are ignored.
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index ee16f40..2082c42 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -19,6 +19,7 @@
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wextra"
+#include <android-base/stringprintf.h>
#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <gtest/gtest.h>
@@ -56,10 +57,7 @@
const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface";
constexpr auto TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface";
-constexpr auto UNIQUE_TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface#0";
-constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0";
constexpr auto LAYER_NAME = "Layer Create and Delete Test";
-constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope";
@@ -105,11 +103,15 @@
system("service call SurfaceFlinger 1020 i32 0 > /dev/null");
}
+std::string getUniqueName(const std::string& name, const Increment& increment) {
+ return base::StringPrintf("%s#%d", name.c_str(), increment.surface_creation().id());
+}
+
int32_t getSurfaceId(const Trace& capturedTrace, const std::string& surfaceName) {
int32_t layerId = 0;
for (const auto& increment : capturedTrace.increment()) {
if (increment.increment_case() == increment.kSurfaceCreation) {
- if (increment.surface_creation().name() == surfaceName) {
+ if (increment.surface_creation().name() == getUniqueName(surfaceName, increment)) {
layerId = increment.surface_creation().id();
}
}
@@ -293,8 +295,8 @@
}
void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) {
- mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_BG_SURFACE_NAME);
- mFGLayerId = getSurfaceId(trace, UNIQUE_TEST_FG_SURFACE_NAME);
+ mBGLayerId = getSurfaceId(trace, TEST_BG_SURFACE_NAME);
+ mFGLayerId = getSurfaceId(trace, TEST_FG_SURFACE_NAME);
}
void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
@@ -752,9 +754,9 @@
}
bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
- bool isMatch(increment.surface_creation().name() == UNIQUE_LAYER_NAME &&
- increment.surface_creation().w() == SIZE_UPDATE &&
- increment.surface_creation().h() == SIZE_UPDATE);
+ bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment) &&
+ increment.surface_creation().w() == SIZE_UPDATE &&
+ increment.surface_creation().h() == SIZE_UPDATE);
if (isMatch && !foundSurface) {
foundSurface = true;
} else if (isMatch && foundSurface) {
@@ -808,7 +810,7 @@
break;
case Increment::IncrementCase::kSurfaceDeletion:
// Find the id of created surface.
- targetId = getSurfaceId(trace, UNIQUE_LAYER_NAME);
+ targetId = getSurfaceId(trace, LAYER_NAME);
foundIncrement = surfaceDeletionFound(increment, targetId, foundIncrement);
break;
case Increment::IncrementCase::kDisplayCreation:
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 2551a19..168b576 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -12,10 +12,10 @@
defaults: ["surfaceflinger_defaults"],
test_suites: ["device-tests"],
srcs: [
- "FakeComposerClient.cpp",
- "FakeComposerService.cpp",
- "FakeComposerUtils.cpp",
- "SFFakeHwc_test.cpp"
+ "FakeComposerClient.cpp",
+ "FakeComposerService.cpp",
+ "FakeComposerUtils.cpp",
+ "SFFakeHwc_test.cpp",
],
require_root: true,
shared_libs: [
@@ -23,12 +23,14 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
"android.hardware.power@1.3",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libfmq",
"libgui",
@@ -43,15 +45,18 @@
],
static_libs: [
"android.hardware.graphics.composer@2.1-resources",
+ "libaidlcommonsupport",
"libcompositionengine",
"libgmock",
"libperfetto_client_experimental",
"librenderengine",
"libtrace_proto",
+ "libaidlcommonsupport",
],
header_libs: [
"android.hardware.graphics.composer@2.4-command-buffer",
"android.hardware.graphics.composer@2.4-hal",
+ "android.hardware.graphics.composer3-command-buffer",
"libsurfaceflinger_headers",
],
}
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index da019a3..f152ced 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -116,15 +116,19 @@
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"android.hardware.power@1.2",
"android.hardware.power@1.3",
- "android.hardware.power-V1-cpp",
+ "android.hardware.power-V2-cpp",
+ "libaidlcommonsupport",
"libcompositionengine_mocks",
"libcompositionengine",
"libframetimeline",
@@ -150,6 +154,7 @@
"android.hardware.graphics.common@1.2",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libEGL",
"libfmq",
@@ -173,6 +178,7 @@
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
"android.hardware.graphics.composer@2.4-command-buffer",
+ "android.hardware.graphics.composer3-command-buffer",
"libsurfaceflinger_headers",
],
}
diff --git a/services/surfaceflinger/tests/unittests/FpsOps.h b/services/surfaceflinger/tests/unittests/FpsOps.h
new file mode 100644
index 0000000..23c2841
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FpsOps.h
@@ -0,0 +1,49 @@
+/*
+ * 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 "Fps.h"
+
+namespace android {
+
+// Pull Fps operators into its namespace to enable ADL for EXPECT_EQ, EXPECT_LT, etc.
+
+inline bool operator==(Fps lhs, Fps rhs) {
+ return fps_approx_ops::operator==(lhs, rhs);
+}
+
+inline bool operator<(Fps lhs, Fps rhs) {
+ return fps_approx_ops::operator<(lhs, rhs);
+}
+
+inline bool operator!=(Fps lhs, Fps rhs) {
+ return fps_approx_ops::operator!=(lhs, rhs);
+}
+
+inline bool operator>(Fps lhs, Fps rhs) {
+ return fps_approx_ops::operator>(lhs, rhs);
+}
+
+inline bool operator<=(Fps lhs, Fps rhs) {
+ return fps_approx_ops::operator<=(lhs, rhs);
+}
+
+inline bool operator>=(Fps lhs, Fps rhs) {
+ return fps_approx_ops::operator>=(lhs, rhs);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FpsTest.cpp b/services/surfaceflinger/tests/unittests/FpsTest.cpp
index db732cf..b44dd89 100644
--- a/services/surfaceflinger/tests/unittests/FpsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsTest.cpp
@@ -15,6 +15,7 @@
*/
#include "Fps.h"
+#include "FpsOps.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -22,77 +23,48 @@
namespace android {
TEST(FpsTest, construct) {
- Fps fpsDefault;
- EXPECT_FALSE(fpsDefault.isValid());
+ EXPECT_FALSE(Fps().isValid());
- Fps fps1(60.0f);
- EXPECT_TRUE(fps1.isValid());
- Fps fps2 = Fps::fromPeriodNsecs(static_cast<nsecs_t>(1e9f / 60.0f));
- EXPECT_TRUE(fps2.isValid());
- EXPECT_TRUE(fps1.equalsWithMargin(fps2));
+ EXPECT_FALSE((0_Hz).isValid());
+ EXPECT_TRUE((120_Hz).isValid());
+ EXPECT_TRUE((0.5_Hz).isValid());
+
+ EXPECT_FALSE(Fps::fromPeriodNsecs(0).isValid());
+
+ const Fps fps = Fps::fromPeriodNsecs(16'666'667);
+ EXPECT_TRUE(fps.isValid());
+ EXPECT_EQ(fps, 60_Hz);
}
TEST(FpsTest, compare) {
- constexpr float kEpsilon = 1e-4f;
- const Fps::EqualsInBuckets equalsInBuckets;
- const Fps::EqualsWithMargin equalsWithMargin;
+ EXPECT_EQ(60_Hz, 60_Hz);
+ EXPECT_EQ(60_Hz, 59.9999_Hz);
+ EXPECT_EQ(60_Hz, 60.0001_Hz);
- EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f)));
- EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f - kEpsilon)));
- EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f + kEpsilon)));
+ EXPECT_LE(60_Hz, 60_Hz);
+ EXPECT_LE(60_Hz, 59.9999_Hz);
+ EXPECT_LE(60_Hz, 60.0001_Hz);
- EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f)));
- EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f - kEpsilon)));
- EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f + kEpsilon)));
+ EXPECT_GE(60_Hz, 60_Hz);
+ EXPECT_GE(60_Hz, 59.9999_Hz);
+ EXPECT_GE(60_Hz, 60.0001_Hz);
- EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f)));
- EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f - kEpsilon)));
- EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f + kEpsilon)));
-
- EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f + kEpsilon)));
- EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f)));
- EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f - kEpsilon)));
-
- EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f + kEpsilon)));
- EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f)));
- EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f - kEpsilon)));
-
- // Fps with difference of 1 should be different
- EXPECT_FALSE(Fps(60.0f).equalsWithMargin(Fps(61.f)));
- EXPECT_TRUE(Fps(60.0f).lessThanWithMargin(Fps(61.f)));
- EXPECT_TRUE(Fps(60.0f).greaterThanWithMargin(Fps(59.f)));
+ // Fps with difference of 1 should be different.
+ EXPECT_NE(60_Hz, 61_Hz);
+ EXPECT_LT(60_Hz, 61_Hz);
+ EXPECT_GT(60_Hz, 59_Hz);
// These are common refresh rates which should be different.
- EXPECT_FALSE(Fps(60.0f).equalsWithMargin(Fps(59.94f)));
- EXPECT_TRUE(Fps(60.0f).greaterThanWithMargin(Fps(59.94f)));
- EXPECT_FALSE(equalsInBuckets(Fps(60.0f), Fps(59.94f)));
- EXPECT_FALSE(equalsWithMargin(Fps(60.0f), Fps(59.94f)));
- EXPECT_NE(std::hash<Fps>()(Fps(60.0f)), std::hash<Fps>()(Fps(59.94f)));
-
- EXPECT_FALSE(Fps(30.0f).equalsWithMargin(Fps(29.97f)));
- EXPECT_TRUE(Fps(30.0f).greaterThanWithMargin(Fps(29.97f)));
- EXPECT_FALSE(equalsInBuckets(Fps(30.0f), Fps(29.97f)));
- EXPECT_FALSE(equalsWithMargin(Fps(30.0f), Fps(29.97f)));
- EXPECT_NE(std::hash<Fps>()(Fps(30.0f)), std::hash<Fps>()(Fps(29.97f)));
+ EXPECT_NE(60_Hz, 59.94_Hz);
+ EXPECT_GT(60_Hz, 59.94_Hz);
+ EXPECT_NE(30_Hz, 29.97_Hz);
+ EXPECT_GT(30_Hz, 29.97_Hz);
}
TEST(FpsTest, getIntValue) {
- EXPECT_EQ(30, Fps(30.1f).getIntValue());
- EXPECT_EQ(31, Fps(30.9f).getIntValue());
- EXPECT_EQ(31, Fps(30.5f).getIntValue());
-}
-
-TEST(FpsTest, equalsInBucketsImpliesEqualHashes) {
- constexpr float kStep = 1e-4f;
- const Fps::EqualsInBuckets equals;
- for (float fps = 30.0f; fps < 31.0f; fps += kStep) {
- const Fps left(fps);
- const Fps right(fps + kStep);
- if (equals(left, right)) {
- ASSERT_EQ(std::hash<Fps>()(left), std::hash<Fps>()(right))
- << "left= " << left << " right=" << right;
- }
- }
+ EXPECT_EQ(30, (30.1_Hz).getIntValue());
+ EXPECT_EQ(31, (30.9_Hz).getIntValue());
+ EXPECT_EQ(31, (30.5_Hz).getIntValue());
}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 97b60e0..9fbaece 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -559,7 +559,7 @@
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
- Fps refreshRate = Fps(11.0);
+ Fps refreshRate = 11_Hz;
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
sLayerNameOne, sGameMode,
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index bb21ad6..e8795fe 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -26,6 +26,7 @@
#include <gtest/gtest.h>
#include <log/log.h>
+#include "FpsOps.h"
#include "Scheduler/LayerHistory.h"
#include "Scheduler/LayerInfo.h"
#include "TestableScheduler.h"
@@ -50,10 +51,10 @@
static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION =
LayerInfo::RefreshRateHistory::HISTORY_DURATION;
- static constexpr Fps LO_FPS{30.f};
+ static constexpr Fps LO_FPS = 30_Hz;
static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs();
- static constexpr Fps HI_FPS{90.f};
+ static constexpr Fps HI_FPS = 90_Hz;
static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs();
LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
@@ -111,8 +112,7 @@
ASSERT_EQ(1, summary.size());
ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- ASSERT_TRUE(desiredRefreshRate.equalsWithMargin(summary[0].desiredRefreshRate))
- << "Frame rate is " << frameRate;
+ ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate);
}
std::shared_ptr<RefreshRateConfigs> mConfigs = std::make_shared<
@@ -149,7 +149,7 @@
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- const nsecs_t time = systemTime();
+ nsecs_t time = systemTime();
// No layers returned if no layers are active.
EXPECT_TRUE(summarizeLayerHistory(time).empty());
@@ -161,6 +161,7 @@
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
+ time += LO_FPS_PERIOD;
}
// Max is returned since we have enough history but there is no timestamp votes.
@@ -169,6 +170,7 @@
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
+ time += LO_FPS_PERIOD;
}
}
@@ -213,7 +215,7 @@
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
- EXPECT_TRUE(LO_FPS.equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+ EXPECT_EQ(LO_FPS, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -306,7 +308,7 @@
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree())
.WillRepeatedly(
- Return(Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::Default)));
+ Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default)));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -319,7 +321,7 @@
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+ EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -328,7 +330,7 @@
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+ EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -338,7 +340,7 @@
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree())
.WillRepeatedly(Return(
- Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::ExactOrMultiple)));
+ Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -352,7 +354,7 @@
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
summarizeLayerHistory(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+ EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -362,7 +364,7 @@
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
summarizeLayerHistory(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+ EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -414,7 +416,7 @@
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_TRUE(HI_FPS.equalsWithMargin(summarizeLayerHistory(time)[1].desiredRefreshRate));
+ EXPECT_EQ(HI_FPS, summarizeLayerHistory(time)[1].desiredRefreshRate);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -429,7 +431,7 @@
ASSERT_EQ(1, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+ EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -448,7 +450,7 @@
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+ EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
EXPECT_EQ(LayerHistory::LayerVoteType::Max, summary[1].vote);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
@@ -458,9 +460,9 @@
summary = summarizeLayerHistory(time);
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+ EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate));
+ EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
@@ -470,9 +472,9 @@
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+ EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate));
+ EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate);
EXPECT_EQ(2, layerCount());
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
@@ -487,7 +489,7 @@
ASSERT_EQ(1, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+ EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -508,7 +510,7 @@
ASSERT_EQ(1, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+ EXPECT_EQ(HI_FPS, summary[0].desiredRefreshRate);
EXPECT_EQ(1, layerCount());
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -585,12 +587,12 @@
EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree())
.WillRepeatedly(Return(
- Layer::FrameRate(Fps(60.0f), Layer::FrameRateCompatibility::ExactOrMultiple)));
+ Layer::FrameRate(60_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false));
EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree())
.WillRepeatedly(Return(
- Layer::FrameRate(Fps(90.0f), Layer::FrameRateCompatibility::ExactOrMultiple)));
+ Layer::FrameRate(90_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
nsecs_t time = systemTime();
@@ -603,7 +605,7 @@
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
summarizeLayerHistory(time)[0].vote);
- EXPECT_TRUE(Fps(60.0f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+ EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
}
@@ -661,7 +663,7 @@
nsecs_t time = systemTime();
for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) {
- recordFramesAndExpect(layer, time, Fps(fps), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, Fps::fromValue(fps), 60_Hz, PRESENT_TIME_HISTORY_SIZE);
}
}
@@ -671,13 +673,13 @@
EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = systemTime();
- recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(30.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(30.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(60.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 30_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 30_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 60_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
}
TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) {
@@ -687,11 +689,11 @@
nsecs_t time = systemTime();
- recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(26.90f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(26.00f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(26.90f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
}
class LayerHistoryTestParameterized : public LayerHistoryTest,
@@ -742,7 +744,7 @@
bool max = false;
bool min = false;
- Fps heuristic{0.0};
+ Fps heuristic;
for (const auto& layer : summarizeLayerHistory(time)) {
if (layer.vote == LayerHistory::LayerVoteType::Heuristic) {
heuristic = layer.desiredRefreshRate;
@@ -754,7 +756,7 @@
}
if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) {
- EXPECT_TRUE(Fps(24.0f).equalsWithMargin(heuristic));
+ EXPECT_EQ(24_Hz, heuristic);
EXPECT_FALSE(max);
if (summarizeLayerHistory(time).size() == 2) {
EXPECT_TRUE(min);
@@ -772,4 +774,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index d6ce5e2..f25994e 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -20,6 +20,7 @@
#include <gtest/gtest.h>
#include "Fps.h"
+#include "FpsOps.h"
#include "Scheduler/LayerHistory.h"
#include "Scheduler/LayerInfo.h"
@@ -47,7 +48,7 @@
TEST_F(LayerInfoTest, prefersPresentTime) {
std::deque<FrameTimeData> frameTimes;
- constexpr auto kExpectedFps = Fps(50.0f);
+ constexpr auto kExpectedFps = 50_Hz;
constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
constexpr int kNumFrames = 10;
for (int i = 1; i <= kNumFrames; i++) {
@@ -58,14 +59,12 @@
setFrameTimes(frameTimes);
const auto averageFrameTime = calculateAverageFrameTime();
ASSERT_TRUE(averageFrameTime.has_value());
- const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
- ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
- << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+ ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
}
TEST_F(LayerInfoTest, fallbacksToQueueTimeIfNoPresentTime) {
std::deque<FrameTimeData> frameTimes;
- constexpr auto kExpectedFps = Fps(50.0f);
+ constexpr auto kExpectedFps = 50_Hz;
constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
constexpr int kNumFrames = 10;
for (int i = 1; i <= kNumFrames; i++) {
@@ -74,17 +73,15 @@
.pendingModeChange = false});
}
setFrameTimes(frameTimes);
- setLastRefreshRate(Fps(20.0f)); // Set to some valid value
+ setLastRefreshRate(20_Hz); // Set to some valid value.
const auto averageFrameTime = calculateAverageFrameTime();
ASSERT_TRUE(averageFrameTime.has_value());
- const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
- ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
- << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+ ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
}
TEST_F(LayerInfoTest, returnsNulloptIfThereWasConfigChange) {
std::deque<FrameTimeData> frameTimesWithoutConfigChange;
- const auto period = Fps(50.0f).getPeriodNsecs();
+ const auto period = (50_Hz).getPeriodNsecs();
constexpr int kNumFrames = 10;
for (int i = 1; i <= kNumFrames; i++) {
frameTimesWithoutConfigChange.push_back(FrameTimeData{.presentTime = period * i,
@@ -124,9 +121,9 @@
// Make sure that this doesn't influence the calculated average FPS.
TEST_F(LayerInfoTest, ignoresSmallPeriods) {
std::deque<FrameTimeData> frameTimes;
- constexpr auto kExpectedFps = Fps(50.0f);
+ constexpr auto kExpectedFps = 50_Hz;
constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
- constexpr auto kSmallPeriod = Fps(250.0f).getPeriodNsecs();
+ constexpr auto kSmallPeriod = (250_Hz).getPeriodNsecs();
constexpr int kNumIterations = 10;
for (int i = 1; i <= kNumIterations; i++) {
frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i,
@@ -141,18 +138,16 @@
setFrameTimes(frameTimes);
const auto averageFrameTime = calculateAverageFrameTime();
ASSERT_TRUE(averageFrameTime.has_value());
- const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
- ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
- << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+ ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
}
// There may be a big period of time between two frames. Make sure that
// this doesn't influence the calculated average FPS.
TEST_F(LayerInfoTest, ignoresLargePeriods) {
std::deque<FrameTimeData> frameTimes;
- constexpr auto kExpectedFps = Fps(50.0f);
+ constexpr auto kExpectedFps = 50_Hz;
constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
- constexpr auto kLargePeriod = Fps(9.0f).getPeriodNsecs();
+ constexpr auto kLargePeriod = (9_Hz).getPeriodNsecs();
auto record = [&](nsecs_t time) {
frameTimes.push_back(
@@ -172,9 +167,7 @@
setFrameTimes(frameTimes);
const auto averageFrameTime = calculateAverageFrameTime();
ASSERT_TRUE(averageFrameTime.has_value());
- const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
- ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
- << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+ ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index a8e3e5e..fc84d48 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -27,15 +27,13 @@
#include <ui/Size.h>
-#include "../../Scheduler/RefreshRateConfigs.h"
#include "DisplayHardware/HWC2.h"
+#include "FpsOps.h"
#include "Scheduler/RefreshRateConfigs.h"
using namespace std::chrono_literals;
-namespace android {
-
-namespace scheduler {
+namespace android::scheduler {
namespace hal = android::hardware::graphics::composer::hal;
@@ -104,33 +102,32 @@
static inline const DisplayModeId HWC_CONFIG_ID_60_FRAC = DisplayModeId(10);
// Test configs
- DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
+ DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, (60_Hz).getPeriodNsecs());
DisplayModePtr mConfig60Frac =
- createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, Fps(59.94f).getPeriodNsecs());
- DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, (59.94_Hz).getPeriodNsecs());
+ DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, (90_Hz).getPeriodNsecs());
DisplayModePtr mConfig90DifferentGroup =
- createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_90, 1, (90_Hz).getPeriodNsecs());
DisplayModePtr mConfig90DifferentResolution =
- createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs(), ui::Size(111, 222));
- DisplayModePtr mConfig72 = createDisplayMode(HWC_CONFIG_ID_72, 0, Fps(72.0f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_90, 0, (90_Hz).getPeriodNsecs(), ui::Size(111, 222));
+ DisplayModePtr mConfig72 = createDisplayMode(HWC_CONFIG_ID_72, 0, (72_Hz).getPeriodNsecs());
DisplayModePtr mConfig72DifferentGroup =
- createDisplayMode(HWC_CONFIG_ID_72, 1, Fps(72.0f).getPeriodNsecs());
- DisplayModePtr mConfig120 =
- createDisplayMode(HWC_CONFIG_ID_120, 0, Fps(120.0f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_72, 1, (72_Hz).getPeriodNsecs());
+ DisplayModePtr mConfig120 = createDisplayMode(HWC_CONFIG_ID_120, 0, (120_Hz).getPeriodNsecs());
DisplayModePtr mConfig120DifferentGroup =
- createDisplayMode(HWC_CONFIG_ID_120, 1, Fps(120.0f).getPeriodNsecs());
- DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_120, 1, (120_Hz).getPeriodNsecs());
+ DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, (30_Hz).getPeriodNsecs());
DisplayModePtr mConfig30DifferentGroup =
- createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_30, 1, (30_Hz).getPeriodNsecs());
DisplayModePtr mConfig30Frac =
- createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, Fps(29.97f).getPeriodNsecs());
- DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, Fps(25.0f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, (29.97_Hz).getPeriodNsecs());
+ DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, (25_Hz).getPeriodNsecs());
DisplayModePtr mConfig25DifferentGroup =
- createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
- DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
- DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, Fps(24.0f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_25, 1, (25_Hz).getPeriodNsecs());
+ DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, (50_Hz).getPeriodNsecs());
+ DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, (24_Hz).getPeriodNsecs());
DisplayModePtr mConfig24Frac =
- createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, Fps(23.976f).getPeriodNsecs());
+ createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, (23.976_Hz).getPeriodNsecs());
// Test device configurations
// The positions of the configs in the arrays below MUST match their IDs. For example,
@@ -206,9 +203,7 @@
}
namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingSupported) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
@@ -219,10 +214,8 @@
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(10), {Fps(60), Fps(60)}}),
- 0);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(20), Fps(40)}}),
- 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20_Hz, 40_Hz}}), 0);
}
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
@@ -256,8 +249,7 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60_Hz, 90_Hz}}), 0);
refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs);
@@ -282,8 +274,7 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60_Hz, 90_Hz}}), 0);
refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs);
@@ -305,8 +296,7 @@
ASSERT_EQ(mExpected60Config, minRate);
ASSERT_EQ(mExpected90Config, performanceRate);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0);
auto minRate60 = getMinRefreshRateByPolicy(*refreshRateConfigs);
auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -329,8 +319,7 @@
EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_90);
}
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0);
{
auto current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_90);
@@ -344,23 +333,19 @@
// If there are no layers we select the default frame rate, which is the max of the primary
// range.
- auto layers = std::vector<LayerRequirement>{};
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate({}, {}));
- ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
+ ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}),
NO_ERROR);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate({}, {}));
// We select max even when this will cause a non-seamless switch.
refreshRateConfigs = std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
/*currentConfigId=*/HWC_CONFIG_ID_60);
ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {Fps(0), Fps(90)}}),
+ {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {0_Hz, 90_Hz}}),
NO_ERROR);
- EXPECT_EQ(mExpected90DifferentGroupConfig,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90DifferentGroupConfig, refreshRateConfigs->getBestRefreshRate({}, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) {
@@ -368,142 +353,109 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
lr.name = "Min";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Heuristic";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(45.0f);
+ lr.desiredRefreshRate = 45_Hz;
lr.name = "45Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(30.0f);
+ lr.desiredRefreshRate = 30_Hz;
lr.name = "30Hz Heuristic";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(24.0f);
+ lr.desiredRefreshRate = 24_Hz;
lr.name = "24Hz Heuristic";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.name = "";
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(45.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 45_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(30.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 30_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(24.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 24_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_90, {Fps(90.0f), Fps(90.0f)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(45.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 45_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(30.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 30_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(24.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 24_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {Fps(0.0f), Fps(120.0f)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0_Hz, 120_Hz}}), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(45.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 45_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(30.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 30_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(24.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 24_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) {
@@ -512,44 +464,37 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60, config);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
lr.name = "Min";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Heuristic";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(45.0f);
+ lr.desiredRefreshRate = 45_Hz;
lr.name = "45Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(30.0f);
+ lr.desiredRefreshRate = 30_Hz;
lr.name = "30Hz Heuristic";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(24.0f);
+ lr.desiredRefreshRate = 24_Hz;
lr.name = "24Hz Heuristic";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) {
@@ -557,37 +502,30 @@
std::make_unique<RefreshRateConfigs>(m60_72_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(45.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 45_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(30.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 30_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(24.0f);
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 24_Hz;
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) {
@@ -595,31 +533,27 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(48.0f);
+ lr2.desiredRefreshRate = 48_Hz;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(48.0f);
+ lr2.desiredRefreshRate = 48_Hz;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) {
@@ -627,91 +561,81 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "60Hz ExplicitDefault";
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
lr1.name = "24Hz Heuristic";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_multipleThreshold) {
@@ -720,91 +644,81 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_60, config);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "60Hz ExplicitDefault";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::Heuristic;
lr1.name = "24Hz Heuristic";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.name = "24Hz ExplicitExactOrMultiple";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr1.desiredRefreshRate = Fps(24.0f);
+ lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.name = "24Hz ExplicitDefault";
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
@@ -812,37 +726,30 @@
std::make_unique<RefreshRateConfigs>(m30_60Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(45.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 45_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(30.0f);
- EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 30_Hz;
+ EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(24.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr.desiredRefreshRate = 24_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) {
@@ -850,60 +757,47 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
lr.name = "Min";
- EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Heuristic";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
- lr.desiredRefreshRate = Fps(45.0f);
+ lr.desiredRefreshRate = 45_Hz;
lr.name = "45Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
- lr.desiredRefreshRate = Fps(30.0f);
+ lr.desiredRefreshRate = 30_Hz;
lr.name = "30Hz Heuristic";
- EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
- lr.desiredRefreshRate = Fps(24.0f);
+ lr.desiredRefreshRate = 24_Hz;
lr.name = "24Hz Heuristic";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
- lr.desiredRefreshRate = Fps(24.0f);
+ lr.desiredRefreshRate = 24_Hz;
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
lr.name = "24Hz ExplicitExactOrMultiple";
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) {
@@ -911,53 +805,45 @@
std::make_unique<RefreshRateConfigs>(m30_60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Max;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(24.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 24_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = Fps(24.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 24_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::Heuristic;
- lr1.desiredRefreshRate = Fps(15.0f);
+ lr1.desiredRefreshRate = 15_Hz;
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(45.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 45_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::Heuristic;
- lr1.desiredRefreshRate = Fps(30.0f);
+ lr1.desiredRefreshRate = 30_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = Fps(45.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 45_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) {
@@ -965,15 +851,15 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
- lr.desiredRefreshRate = Fps(fps);
- const auto& refreshRate =
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
- EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+ lr.desiredRefreshRate = Fps::fromValue(fps);
+ const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+ EXPECT_EQ(mExpected60Config, refreshRate)
+ << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
}
}
@@ -983,15 +869,15 @@
std::make_unique<RefreshRateConfigs>(m60_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_60, config);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
- lr.desiredRefreshRate = Fps(fps);
- const auto& refreshRate =
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
- EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+ lr.desiredRefreshRate = Fps::fromValue(fps);
+ const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+ EXPECT_EQ(mExpected60Config, refreshRate)
+ << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
}
}
@@ -1000,39 +886,35 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::Heuristic;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = Fps(90.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 90_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::ExplicitDefault;
- lr1.desiredRefreshRate = Fps(90.0f);
+ lr1.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::Heuristic;
- lr1.desiredRefreshRate = Fps(90.0f);
+ lr1.desiredRefreshRate = 90_Hz;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr2.desiredRefreshRate = Fps(60.0f);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ lr2.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, testInPolicy) {
- ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(Fps(60.000004f), Fps(60.000004f)));
- ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(Fps(59.0f), Fps(60.1f)));
- ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(75.0f), Fps(90.0f)));
- ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(60.0011f), Fps(90.0f)));
- ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(50.0f), Fps(59.998f)));
+ ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(60.000004_Hz, 60.000004_Hz));
+ ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(59_Hz, 60.1_Hz));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(75_Hz, 90_Hz));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(60.0011_Hz, 90_Hz));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(50_Hz, 59.998_Hz));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
@@ -1040,15 +922,15 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
- lr.desiredRefreshRate = Fps(fps);
- const auto& refreshRate =
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
- EXPECT_EQ(mExpected90Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+ lr.desiredRefreshRate = Fps::fromValue(fps);
+ const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+ EXPECT_EQ(mExpected90Config, refreshRate)
+ << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
}
}
@@ -1057,53 +939,47 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::ExplicitDefault;
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.name = "90Hz ExplicitDefault";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(30.0f);
+ lr1.desiredRefreshRate = 30_Hz;
lr1.name = "30Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(30.0f);
+ lr1.desiredRefreshRate = 30_Hz;
lr1.name = "30Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
@@ -1111,52 +987,46 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
// The other layer starts to provide buffers
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(90.0f);
+ lr2.desiredRefreshRate = 90_Hz;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, touchConsidered) {
@@ -1165,55 +1035,50 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false}, &consideredSignals);
+ refreshRateConfigs->getBestRefreshRate({}, {}, &consideredSignals);
EXPECT_EQ(false, consideredSignals.touch);
- refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = false}, &consideredSignals);
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = true}, &consideredSignals);
EXPECT_EQ(true, consideredSignals.touch);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.name = "60Hz Heuristic";
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
- &consideredSignals);
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals);
EXPECT_EQ(true, consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitDefault;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.name = "60Hz Heuristic";
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
- &consideredSignals);
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals);
EXPECT_EQ(false, consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.name = "60Hz Heuristic";
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
- &consideredSignals);
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals);
EXPECT_EQ(true, consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitDefault;
- lr1.desiredRefreshRate = Fps(60.0f);
+ lr1.desiredRefreshRate = 60_Hz;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.desiredRefreshRate = Fps(60.0f);
+ lr2.desiredRefreshRate = 60_Hz;
lr2.name = "60Hz Heuristic";
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
- &consideredSignals);
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals);
EXPECT_EQ(false, consideredSignals.touch);
}
@@ -1222,47 +1087,44 @@
std::make_unique<RefreshRateConfigs>(m60_90_72_120Device, /*currentConfigId=*/
HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
// Prepare a table with the vote and the expected refresh rate
- const std::vector<std::pair<float, float>> testCases = {
- {130, 120}, {120, 120}, {119, 120}, {110, 120},
+ const std::initializer_list<std::pair<Fps, Fps>> testCases = {
+ {130_Hz, 120_Hz}, {120_Hz, 120_Hz}, {119_Hz, 120_Hz}, {110_Hz, 120_Hz},
- {100, 90}, {90, 90}, {89, 90},
+ {100_Hz, 90_Hz}, {90_Hz, 90_Hz}, {89_Hz, 90_Hz},
- {80, 72}, {73, 72}, {72, 72}, {71, 72}, {70, 72},
+ {80_Hz, 72_Hz}, {73_Hz, 72_Hz}, {72_Hz, 72_Hz}, {71_Hz, 72_Hz}, {70_Hz, 72_Hz},
- {65, 60}, {60, 60}, {59, 60}, {58, 60},
+ {65_Hz, 60_Hz}, {60_Hz, 60_Hz}, {59_Hz, 60_Hz}, {58_Hz, 60_Hz},
- {55, 90}, {50, 90}, {45, 90},
+ {55_Hz, 90_Hz}, {50_Hz, 90_Hz}, {45_Hz, 90_Hz},
- {42, 120}, {40, 120}, {39, 120},
+ {42_Hz, 120_Hz}, {40_Hz, 120_Hz}, {39_Hz, 120_Hz},
- {37, 72}, {36, 72}, {35, 72},
+ {37_Hz, 72_Hz}, {36_Hz, 72_Hz}, {35_Hz, 72_Hz},
- {30, 60},
+ {30_Hz, 60_Hz},
};
- for (const auto& test : testCases) {
+ for (auto [desired, expected] : testCases) {
lr.vote = LayerVoteType::ExplicitDefault;
- lr.desiredRefreshRate = Fps(test.first);
+ lr.desiredRefreshRate = desired;
std::stringstream ss;
- ss << "ExplicitDefault " << test.first << " fps";
+ ss << "ExplicitDefault " << desired;
lr.name = ss.str();
- const auto& refreshRate =
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
- EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second)))
- << "Expecting " << test.first << "fps => " << test.second << "Hz"
- << " but it was " << refreshRate.getFps();
+ const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+ EXPECT_EQ(refreshRate.getFps(), expected);
}
}
TEST_F(RefreshRateConfigsTest,
getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) {
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
// Test that 23.976 will choose 24 if 23.976 is not supported
@@ -1273,11 +1135,9 @@
std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr.desiredRefreshRate = Fps(23.976f);
- lr.name = "ExplicitExactOrMultiple 23.976 fps";
- EXPECT_EQ(HWC_CONFIG_ID_24,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ lr.desiredRefreshRate = 23.976_Hz;
+ lr.name = "ExplicitExactOrMultiple 23.976 Hz";
+ EXPECT_EQ(HWC_CONFIG_ID_24, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
// Test that 24 will choose 23.976 if 24 is not supported
@@ -1286,11 +1146,10 @@
mConfig30Frac, mConfig60, mConfig60Frac};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
- lr.desiredRefreshRate = Fps(24.f);
- lr.name = "ExplicitExactOrMultiple 24 fps";
+ lr.desiredRefreshRate = 24_Hz;
+ lr.name = "ExplicitExactOrMultiple 24 Hz";
EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
// Test that 29.97 will prefer 59.94 over 60 and 30
@@ -1299,16 +1158,15 @@
mConfig30, mConfig60, mConfig60Frac};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
- lr.desiredRefreshRate = Fps(29.97f);
- lr.name = "ExplicitExactOrMultiple 29.97f fps";
+ lr.desiredRefreshRate = 29.97_Hz;
+ lr.name = "ExplicitExactOrMultiple 29.97 Hz";
EXPECT_EQ(HWC_CONFIG_ID_60_FRAC,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) {
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
// Test that voting for supported refresh rate will select this refresh rate
@@ -1317,19 +1175,15 @@
std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- for (auto desiredRefreshRate : {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}) {
+ for (auto desired : {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz}) {
lr.vote = LayerVoteType::ExplicitExact;
- lr.desiredRefreshRate = Fps(desiredRefreshRate);
+ lr.desiredRefreshRate = desired;
std::stringstream ss;
- ss << "ExplicitExact " << desiredRefreshRate << " fps";
+ ss << "ExplicitExact " << desired;
lr.name = ss.str();
- auto selecteRefreshRate =
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
-
- EXPECT_TRUE(selecteRefreshRate.getFps().equalsWithMargin(lr.desiredRefreshRate))
- << "Expecting " << lr.desiredRefreshRate << " but it was "
- << selecteRefreshRate.getFps();
+ auto selectedRefreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+ EXPECT_EQ(selectedRefreshRate.getFps(), lr.desiredRefreshRate);
}
}
@@ -1340,11 +1194,9 @@
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
lr.vote = LayerVoteType::ExplicitExact;
- lr.desiredRefreshRate = Fps(23.976f);
- lr.name = "ExplicitExact 23.976 fps";
- EXPECT_EQ(HWC_CONFIG_ID_24,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ lr.desiredRefreshRate = 23.976_Hz;
+ lr.name = "ExplicitExact 23.976 Hz";
+ EXPECT_EQ(HWC_CONFIG_ID_24, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
// Test that 24 will choose 23.976 if 24 is not supported
@@ -1353,11 +1205,10 @@
mConfig30Frac, mConfig60, mConfig60Frac};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
- lr.desiredRefreshRate = Fps(24.f);
- lr.name = "ExplicitExact 24 fps";
+ lr.desiredRefreshRate = 24_Hz;
+ lr.name = "ExplicitExact 24 Hz";
EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
}
@@ -1368,15 +1219,15 @@
/*currentConfigId=*/HWC_CONFIG_ID_90);
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_90, {Fps(90.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
+ {HWC_CONFIG_ID_90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}),
0);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
RefreshRateConfigs::GlobalSignals consideredSignals;
lr.vote = LayerVoteType::ExplicitDefault;
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz ExplicitDefault";
lr.focused = true;
EXPECT_EQ(mExpected60Config,
@@ -1392,18 +1243,17 @@
/*currentConfigId=*/HWC_CONFIG_ID_60);
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {Fps(60.f), Fps(60.f)}, {Fps(60.f), Fps(90.f)}}),
+ {HWC_CONFIG_ID_60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}}),
0);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::ExplicitDefault;
- lr.desiredRefreshRate = Fps(90.0f);
+ lr.desiredRefreshRate = 90_Hz;
lr.name = "90Hz ExplicitDefault";
lr.focused = true;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.idle = true}));
}
TEST_F(RefreshRateConfigsTest,
@@ -1413,72 +1263,61 @@
/*currentConfigId=*/HWC_CONFIG_ID_90);
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_90, {Fps(90.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
+ {HWC_CONFIG_ID_90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}),
0);
RefreshRateConfigs::GlobalSignals consideredSignals;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false},
- &consideredSignals));
+ refreshRateConfigs->getBestRefreshRate({}, {}, &consideredSignals));
EXPECT_EQ(false, consideredSignals.touch);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz ExplicitExactOrMultiple";
lr.focused = false;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.focused = true;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::ExplicitDefault;
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz ExplicitDefault";
lr.focused = false;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.focused = true;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Heuristic;
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Heuristic";
lr.focused = false;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.focused = true;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Max;
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Max";
lr.focused = false;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.focused = true;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.vote = LayerVoteType::Min;
- lr.desiredRefreshRate = Fps(60.0f);
+ lr.desiredRefreshRate = 60_Hz;
lr.name = "60Hz Min";
lr.focused = false;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
lr.focused = true;
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, groupSwitchingNotAllowed) {
@@ -1488,17 +1327,15 @@
// The default policy doesn't allow group switching. Verify that no
// group switches are performed.
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitDefault;
- layer.desiredRefreshRate = Fps(90.0f);
+ layer.desiredRefreshRate = 90_Hz;
layer.seamlessness = Seamlessness::SeamedAndSeamless;
layer.name = "90Hz ExplicitDefault";
layer.focused = true;
- ASSERT_EQ(HWC_CONFIG_ID_60,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) {
@@ -1510,16 +1347,14 @@
policy.allowGroupSwitching = true;
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitDefault;
- layer.desiredRefreshRate = Fps(90.0f);
+ layer.desiredRefreshRate = 90_Hz;
layer.seamlessness = Seamlessness::SeamedAndSeamless;
layer.name = "90Hz ExplicitDefault";
layer.focused = true;
- ASSERT_EQ(HWC_CONFIG_ID_90,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) {
@@ -1532,16 +1367,14 @@
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
// Verify that we won't change the group if seamless switch is required.
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitDefault;
- layer.desiredRefreshRate = Fps(90.0f);
+ layer.desiredRefreshRate = 90_Hz;
layer.seamlessness = Seamlessness::OnlySeamless;
layer.name = "90Hz ExplicitDefault";
layer.focused = true;
- ASSERT_EQ(HWC_CONFIG_ID_60,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) {
@@ -1556,16 +1389,14 @@
refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
// Verify that we won't do a seamless switch if we request the same mode as the default
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitDefault;
- layer.desiredRefreshRate = Fps(60.0f);
+ layer.desiredRefreshRate = 60_Hz;
layer.seamlessness = Seamlessness::OnlySeamless;
layer.name = "60Hz ExplicitDefault";
layer.focused = true;
- ASSERT_EQ(HWC_CONFIG_ID_90,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) {
@@ -1582,17 +1413,15 @@
// Verify that if the current config is in another group and there are no layers with
// seamlessness=SeamedAndSeamless we'll go back to the default group.
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitDefault;
- layer.desiredRefreshRate = Fps(60.0f);
+ layer.desiredRefreshRate = 60_Hz;
layer.seamlessness = Seamlessness::Default;
layer.name = "60Hz ExplicitDefault";
layer.focused = true;
- ASSERT_EQ(HWC_CONFIG_ID_60,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) {
@@ -1608,9 +1437,9 @@
// If there's a layer with seamlessness=SeamedAndSeamless, another layer with
// seamlessness=OnlySeamless can't change the mode group.
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
layers[0].vote = LayerVoteType::ExplicitDefault;
- layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].desiredRefreshRate = 60_Hz;
layers[0].seamlessness = Seamlessness::OnlySeamless;
layers[0].name = "60Hz ExplicitDefault";
layers[0].focused = true;
@@ -1618,13 +1447,11 @@
layers.push_back(LayerRequirement{.weight = 0.5f});
layers[1].vote = LayerVoteType::ExplicitDefault;
layers[1].seamlessness = Seamlessness::SeamedAndSeamless;
- layers[1].desiredRefreshRate = Fps(90.0f);
+ layers[1].desiredRefreshRate = 90_Hz;
layers[1].name = "90Hz ExplicitDefault";
layers[1].focused = false;
- ASSERT_EQ(HWC_CONFIG_ID_90,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) {
@@ -1644,23 +1471,21 @@
// For example, this may happen when a video playback requests and gets a seamed switch,
// but another layer (with default seamlessness) starts animating. The animating layer
// should not cause a seamed switch.
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
layers[0].seamlessness = Seamlessness::Default;
- layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].desiredRefreshRate = 60_Hz;
layers[0].focused = true;
layers[0].vote = LayerVoteType::ExplicitDefault;
layers[0].name = "60Hz ExplicitDefault";
layers.push_back(LayerRequirement{.weight = 0.1f});
layers[1].seamlessness = Seamlessness::SeamedAndSeamless;
- layers[1].desiredRefreshRate = Fps(90.0f);
+ layers[1].desiredRefreshRate = 90_Hz;
layers[1].focused = true;
layers[1].vote = LayerVoteType::ExplicitDefault;
layers[1].name = "90Hz ExplicitDefault";
- ASSERT_EQ(HWC_CONFIG_ID_90,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) {
@@ -1677,23 +1502,21 @@
// Layer with seamlessness=Default can change the mode group if there's a not
// focused layer with seamlessness=SeamedAndSeamless. This happens for example,
// when in split screen mode the user switches between the two visible applications.
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
layers[0].seamlessness = Seamlessness::Default;
- layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].desiredRefreshRate = 60_Hz;
layers[0].focused = true;
layers[0].vote = LayerVoteType::ExplicitDefault;
layers[0].name = "60Hz ExplicitDefault";
layers.push_back(LayerRequirement{.weight = 0.7f});
layers[1].seamlessness = Seamlessness::SeamedAndSeamless;
- layers[1].desiredRefreshRate = Fps(90.0f);
+ layers[1].desiredRefreshRate = 90_Hz;
layers[1].focused = false;
layers[1].vote = LayerVoteType::ExplicitDefault;
layers[1].name = "90Hz ExplicitDefault";
- ASSERT_EQ(HWC_CONFIG_ID_60,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) {
@@ -1707,22 +1530,18 @@
policy.allowGroupSwitching = true;
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitExactOrMultiple;
- layer.desiredRefreshRate = Fps(60.0f);
+ layer.desiredRefreshRate = 60_Hz;
layer.seamlessness = Seamlessness::SeamedAndSeamless;
layer.name = "60Hz ExplicitExactOrMultiple";
layer.focused = true;
- ASSERT_EQ(HWC_CONFIG_ID_60,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_120);
- ASSERT_EQ(HWC_CONFIG_ID_120,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_120, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) {
@@ -1736,31 +1555,27 @@
policy.allowGroupSwitching = true;
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
- auto layers = std::vector<
- LayerRequirement>{LayerRequirement{.name = "60Hz ExplicitDefault",
- .vote = LayerVoteType::ExplicitDefault,
- .desiredRefreshRate = Fps(60.0f),
- .seamlessness = Seamlessness::SeamedAndSeamless,
- .weight = 0.5f,
- .focused = false},
- LayerRequirement{.name = "25Hz ExplicitExactOrMultiple",
- .vote = LayerVoteType::ExplicitExactOrMultiple,
- .desiredRefreshRate = Fps(25.0f),
- .seamlessness = Seamlessness::OnlySeamless,
- .weight = 1.0f,
- .focused = true}};
+ std::vector<LayerRequirement> layers = {{.name = "60Hz ExplicitDefault",
+ .vote = LayerVoteType::ExplicitDefault,
+ .desiredRefreshRate = 60_Hz,
+ .seamlessness = Seamlessness::SeamedAndSeamless,
+ .weight = 0.5f,
+ .focused = false},
+ {.name = "25Hz ExplicitExactOrMultiple",
+ .vote = LayerVoteType::ExplicitExactOrMultiple,
+ .desiredRefreshRate = 25_Hz,
+ .seamlessness = Seamlessness::OnlySeamless,
+ .weight = 1.f,
+ .focused = true}};
- ASSERT_EQ(HWC_CONFIG_ID_50,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_50, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
auto& seamedLayer = layers[0];
- seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = Fps(30.0f);
+ seamedLayer.desiredRefreshRate = 30_Hz;
+ seamedLayer.name = "30Hz ExplicitDefault";
refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_30);
- ASSERT_EQ(HWC_CONFIG_ID_25,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_25, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, minLayersDontTrigerSeamedSwitch) {
@@ -1774,14 +1589,10 @@
policy.allowGroupSwitching = true;
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.name = "Min",
- .vote = LayerVoteType::Min,
- .weight = 1.f,
- .focused = true}};
+ std::vector<LayerRequirement> layers = {
+ {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}};
- ASSERT_EQ(HWC_CONFIG_ID_90,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
- .getModeId());
+ ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
}
TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
@@ -1789,59 +1600,58 @@
std::make_unique<RefreshRateConfigs>(m30_60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
layers[0].name = "Test layer";
+ struct Args {
+ bool touch = false;
+ bool focused = true;
+ };
+
// Return the config ID from calling getBestRefreshRate() for a single layer with the
// given voteType and fps.
- auto getFrameRate = [&](LayerVoteType voteType, Fps fps, bool touchActive = false,
- bool focused = true) -> DisplayModeId {
+ auto getFrameRate = [&](LayerVoteType voteType, Fps fps, Args args = {}) -> DisplayModeId {
layers[0].vote = voteType;
layers[0].desiredRefreshRate = fps;
- layers[0].focused = focused;
- return refreshRateConfigs->getBestRefreshRate(layers, {.touch = touchActive, .idle = false})
- .getModeId();
+ layers[0].focused = args.focused;
+ return refreshRateConfigs->getBestRefreshRate(layers, {.touch = args.touch}).getModeId();
};
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {Fps(30.f), Fps(60.f)}, {Fps(30.f), Fps(90.f)}}),
+ {HWC_CONFIG_ID_60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}),
0);
- EXPECT_EQ(HWC_CONFIG_ID_60,
- refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false})
- .getModeId());
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate({}, {}).getModeId());
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz));
- // Layers not focused are not allowed to override primary config
+ // Unfocused layers are not allowed to override primary config.
EXPECT_EQ(HWC_CONFIG_ID_60,
- getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f), /*touch=*/false,
- /*focused=*/false));
+ getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.focused = false}));
EXPECT_EQ(HWC_CONFIG_ID_60,
- getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f), /*touch=*/false,
- /*focused=*/false));
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.focused = false}));
// Touch boost should be restricted to the primary range.
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f), /*touch=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz, {.touch = true}));
// When we're higher than the primary range max due to a layer frame rate setting, touch boost
// shouldn't drag us back down to the primary range max.
EXPECT_EQ(HWC_CONFIG_ID_90,
- getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f), /*touch=*/true));
+ getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.touch = true}));
EXPECT_EQ(HWC_CONFIG_ID_60,
- getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f), /*touch=*/true));
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.touch = true}));
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {Fps(60.f), Fps(60.f)}, {Fps(60.f), Fps(60.f)}}),
+ {HWC_CONFIG_ID_60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}}),
0);
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f)));
- EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f)));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz));
}
TEST_F(RefreshRateConfigsTest, idle) {
@@ -1849,12 +1659,12 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
layers[0].name = "Test layer";
const auto getIdleFrameRate = [&](LayerVoteType voteType, bool touchActive) -> DisplayModeId {
layers[0].vote = voteType;
- layers[0].desiredRefreshRate = Fps(90.f);
+ layers[0].desiredRefreshRate = 90_Hz;
RefreshRateConfigs::GlobalSignals consideredSignals;
const auto configId =
refreshRateConfigs
@@ -1867,7 +1677,7 @@
};
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_60, {Fps(60.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
+ {HWC_CONFIG_ID_60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}),
0);
// Idle should be lower priority than touch boost.
@@ -1898,8 +1708,7 @@
// Idle should be applied rather than the current config when there are no layers.
EXPECT_EQ(HWC_CONFIG_ID_60,
- refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = true})
- .getModeId());
+ refreshRateConfigs->getBestRefreshRate({}, {.idle = true}).getModeId());
}
TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) {
@@ -1908,23 +1717,23 @@
/*currentConfigId=*/HWC_CONFIG_ID_60);
for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) {
- const auto knownFrameRate = findClosestKnownFrameRate(*refreshRateConfigs, Fps(fps));
+ const auto knownFrameRate =
+ findClosestKnownFrameRate(*refreshRateConfigs, Fps::fromValue(fps));
Fps expectedFrameRate;
if (fps < 26.91f) {
- expectedFrameRate = Fps(24.0f);
+ expectedFrameRate = 24_Hz;
} else if (fps < 37.51f) {
- expectedFrameRate = Fps(30.0f);
+ expectedFrameRate = 30_Hz;
} else if (fps < 52.51f) {
- expectedFrameRate = Fps(45.0f);
+ expectedFrameRate = 45_Hz;
} else if (fps < 66.01f) {
- expectedFrameRate = Fps(60.0f);
+ expectedFrameRate = 60_Hz;
} else if (fps < 81.01f) {
- expectedFrameRate = Fps(72.0f);
+ expectedFrameRate = 72_Hz;
} else {
- expectedFrameRate = Fps(90.0f);
+ expectedFrameRate = 90_Hz;
}
- EXPECT_TRUE(expectedFrameRate.equalsWithMargin(knownFrameRate))
- << "findClosestKnownFrameRate(" << fps << ") = " << knownFrameRate;
+ EXPECT_EQ(expectedFrameRate, knownFrameRate);
}
}
@@ -1933,38 +1742,32 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- struct ExpectedRate {
- Fps rate;
- const RefreshRate& expected;
+ struct Expectation {
+ Fps fps;
+ const RefreshRate& refreshRate;
};
- /* clang-format off */
- std::vector<ExpectedRate> knownFrameRatesExpectations = {
- {Fps(24.0f), mExpected60Config},
- {Fps(30.0f), mExpected60Config},
- {Fps(45.0f), mExpected90Config},
- {Fps(60.0f), mExpected60Config},
- {Fps(72.0f), mExpected90Config},
- {Fps(90.0f), mExpected90Config},
+ const std::initializer_list<Expectation> knownFrameRatesExpectations = {
+ {24_Hz, mExpected60Config}, {30_Hz, mExpected60Config}, {45_Hz, mExpected90Config},
+ {60_Hz, mExpected60Config}, {72_Hz, mExpected90Config}, {90_Hz, mExpected90Config},
};
- /* clang-format on */
// Make sure the test tests all the known frame rate
const auto knownFrameRateList = getKnownFrameRate(*refreshRateConfigs);
- const auto equal =
- std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
- knownFrameRatesExpectations.begin(),
- [](Fps a, const ExpectedRate& b) { return a.equalsWithMargin(b.rate); });
+ const bool equal = std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
+ knownFrameRatesExpectations.begin(),
+ [](Fps fps, const Expectation& expected) {
+ return isApproxEqual(fps, expected.fps);
+ });
EXPECT_TRUE(equal);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
layer.vote = LayerVoteType::Heuristic;
- for (const auto& expectedRate : knownFrameRatesExpectations) {
- layer.desiredRefreshRate = expectedRate.rate;
- const auto& refreshRate =
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
- EXPECT_EQ(expectedRate.expected, refreshRate);
+
+ for (const auto& [fps, refreshRate] : knownFrameRatesExpectations) {
+ layer.desiredRefreshRate = fps;
+ EXPECT_EQ(refreshRate, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
}
@@ -1973,40 +1776,33 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 0.5f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
auto& explicitExactLayer = layers[0];
auto& explicitExactOrMultipleLayer = layers[1];
explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
- explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+ explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
explicitExactLayer.vote = LayerVoteType::ExplicitExact;
explicitExactLayer.name = "ExplicitExact";
- explicitExactLayer.desiredRefreshRate = Fps(30);
+ explicitExactLayer.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
- explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120);
- explicitExactLayer.desiredRefreshRate = Fps(60);
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz;
+ explicitExactLayer.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- explicitExactLayer.desiredRefreshRate = Fps(72);
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ explicitExactLayer.desiredRefreshRate = 72_Hz;
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- explicitExactLayer.desiredRefreshRate = Fps(90);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ explicitExactLayer.desiredRefreshRate = 90_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- explicitExactLayer.desiredRefreshRate = Fps(120);
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ explicitExactLayer.desiredRefreshRate = 120_Hz;
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) {
@@ -2015,40 +1811,33 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_60, config);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 0.5f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
auto& explicitExactLayer = layers[0];
auto& explicitExactOrMultipleLayer = layers[1];
explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
- explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+ explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
explicitExactLayer.vote = LayerVoteType::ExplicitExact;
explicitExactLayer.name = "ExplicitExact";
- explicitExactLayer.desiredRefreshRate = Fps(30);
+ explicitExactLayer.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
- explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120);
- explicitExactLayer.desiredRefreshRate = Fps(60);
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz;
+ explicitExactLayer.desiredRefreshRate = 60_Hz;
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- explicitExactLayer.desiredRefreshRate = Fps(72);
- EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ explicitExactLayer.desiredRefreshRate = 72_Hz;
+ EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- explicitExactLayer.desiredRefreshRate = Fps(90);
- EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ explicitExactLayer.desiredRefreshRate = 90_Hz;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
- explicitExactLayer.desiredRefreshRate = Fps(120);
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ explicitExactLayer.desiredRefreshRate = 120_Hz;
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCached) {
@@ -2059,26 +1848,20 @@
/*currentConfigId=*/HWC_CONFIG_ID_60);
setLastBestRefreshRateInvocation(*refreshRateConfigs,
- GetBestRefreshRateInvocation{.layerRequirements = std::vector<
- LayerRequirement>(),
- .globalSignals = {.touch = true,
+ GetBestRefreshRateInvocation{.globalSignals = {.touch = true,
.idle = true},
.outSignalsConsidered =
- {.touch = true,
- .idle = false},
+ {.touch = true},
.resultingBestRefreshRate =
createRefreshRate(
mConfig90)});
EXPECT_EQ(createRefreshRate(mConfig90),
- refreshRateConfigs->getBestRefreshRate(std::vector<LayerRequirement>(),
- {.touch = true, .idle = true}));
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true}));
- const GlobalSignals cachedSignalsConsidered{.touch = true, .idle = false};
+ const GlobalSignals cachedSignalsConsidered{.touch = true};
setLastBestRefreshRateInvocation(*refreshRateConfigs,
- GetBestRefreshRateInvocation{.layerRequirements = std::vector<
- LayerRequirement>(),
- .globalSignals = {.touch = true,
+ GetBestRefreshRateInvocation{.globalSignals = {.touch = true,
.idle = true},
.outSignalsConsidered =
cachedSignalsConsidered,
@@ -2088,8 +1871,7 @@
GlobalSignals signalsConsidered;
EXPECT_EQ(createRefreshRate(mConfig30),
- refreshRateConfigs->getBestRefreshRate(std::vector<LayerRequirement>(),
- {.touch = true, .idle = true},
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true},
&signalsConsidered));
EXPECT_EQ(cachedSignalsConsidered, signalsConsidered);
@@ -2104,8 +1886,7 @@
ASSERT_FALSE(getLastBestRefreshRateInvocation(*refreshRateConfigs).has_value());
GlobalSignals globalSignals{.touch = true, .idle = true};
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 0.5f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
const auto lastResult =
refreshRateConfigs->getBestRefreshRate(layers, globalSignals,
/* outSignalsConsidered */ nullptr);
@@ -2129,30 +1910,25 @@
std::make_unique<RefreshRateConfigs>(m60_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_60, config);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
- LayerRequirement{.weight = 0.5f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
auto& explicitExactLayer = layers[0];
auto& explicitExactOrMultipleLayer = layers[1];
explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
- explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+ explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
explicitExactLayer.vote = LayerVoteType::ExplicitExact;
explicitExactLayer.name = "ExplicitExact";
- explicitExactLayer.desiredRefreshRate = Fps(30);
+ explicitExactLayer.desiredRefreshRate = 30_Hz;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
@@ -2161,21 +1937,19 @@
std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
/*currentConfigId=*/HWC_CONFIG_ID_60, config);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 0.5f},
- LayerRequirement{.weight = 0.5f}};
+ std::vector<LayerRequirement> layers = {{.weight = 0.5f}, {.weight = 0.5f}};
auto& explicitDefaultLayer = layers[0];
auto& explicitExactOrMultipleLayer = layers[1];
explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
- explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+ explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault;
explicitDefaultLayer.name = "ExplicitDefault";
- explicitDefaultLayer.desiredRefreshRate = Fps(59.94f);
+ explicitDefaultLayer.desiredRefreshRate = 59.94_Hz;
- EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
}
// b/190578904
@@ -2186,29 +1960,26 @@
DisplayModes displayModes;
for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
constexpr int32_t kGroup = 0;
- const auto refreshRate = Fps(static_cast<float>(fps));
+ const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
displayModes.push_back(
createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs()));
}
- const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(displayModes,
/*currentConfigId=*/displayModes[0]->getId());
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
layers[0].desiredRefreshRate = fps;
layers[0].vote = vote;
EXPECT_EQ(fps.getIntValue(),
- refreshRateConfigs->getBestRefreshRate(layers, globalSignals)
- .getFps()
- .getIntValue())
+ refreshRateConfigs->getBestRefreshRate(layers, {}).getFps().getIntValue())
<< "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote);
};
for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
- const auto refreshRate = Fps(static_cast<float>(fps));
+ const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
testRefreshRate(refreshRate, LayerVoteType::Heuristic);
testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault);
testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple);
@@ -2232,18 +2003,15 @@
EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(60, 90), current 60Hz => TurnOn.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(90)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 90_Hz}}), 0);
EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(60, 60), current 60Hz => TurnOff
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0);
EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(90, 90), current 90Hz => TurnOff.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0);
EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
}
@@ -2255,23 +2023,19 @@
std::make_unique<RefreshRateConfigs>(m60_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_120);
// SetPolicy(0, 60), current 60Hz => TurnOn.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(0), Fps(60)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0_Hz, 60_Hz}}), 0);
EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(60, 60), current 60Hz => TurnOff.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0);
EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(60, 120), current 60Hz => TurnOn.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(120)}}),
- 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 120_Hz}}), 0);
EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
// SetPolicy(120, 120), current 120Hz => TurnOff.
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
- {HWC_CONFIG_ID_120, {Fps(120), Fps(120)}}),
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_120, {120_Hz, 120_Hz}}),
0);
EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
}
@@ -2281,7 +2045,7 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_30);
- const auto frameRate = Fps(30.f);
+ const auto frameRate = 30_Hz;
Fps displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
@@ -2303,39 +2067,38 @@
refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
- EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.5f)));
+ EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, 22.5_Hz));
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(25.f)));
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(23.976f)));
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(30.f), Fps(29.97f)));
- EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(60.f), Fps(59.94f)));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 25_Hz));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 23.976_Hz));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(30_Hz, 29.97_Hz));
+ EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(60_Hz, 59.94_Hz));
}
TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.976f), Fps(24.f)));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(23.976f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(23.976_Hz, 24_Hz));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(24_Hz, 23.976_Hz));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(30.f)));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(29.97f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 30_Hz));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(30_Hz, 29.97_Hz));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(60.f)));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(59.94f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(59.94_Hz, 60_Hz));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(60_Hz, 59.94_Hz));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(60.f)));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(29.97f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 60_Hz));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(60_Hz, 29.97_Hz));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(30.f)));
- EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(59.94f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(59.94_Hz, 30_Hz));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(30_Hz, 59.94_Hz));
- const std::vector<float> refreshRates = {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f};
+ const auto refreshRates = {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz};
for (auto refreshRate : refreshRates) {
- EXPECT_FALSE(
- RefreshRateConfigs::isFractionalPairOrMultiple(Fps(refreshRate), Fps(refreshRate)));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(refreshRate, refreshRate));
}
- EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(25.f)));
- EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.978f), Fps(25.f)));
- EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(59.94f)));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(24_Hz, 25_Hz));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(23.978_Hz, 25_Hz));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 59.94_Hz));
}
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) {
@@ -2343,9 +2106,7 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
HWC_CONFIG_ID_120);
- auto layers = std::vector<LayerRequirement>{};
- ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false)
- .empty());
+ ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides({}, 120_Hz, {}).empty());
}
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) {
@@ -2354,42 +2115,36 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
HWC_CONFIG_ID_120, config);
- auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
layers[0].name = "Test layer";
layers[0].ownerUid = 1234;
- layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].desiredRefreshRate = 60_Hz;
layers[0].vote = LayerVoteType::ExplicitDefault;
- auto frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
layers[0].vote = LayerVoteType::NoVote;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_TRUE(frameRateOverrides.empty());
layers[0].vote = LayerVoteType::Min;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_TRUE(frameRateOverrides.empty());
layers[0].vote = LayerVoteType::Max;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_TRUE(frameRateOverrides.empty());
layers[0].vote = LayerVoteType::Heuristic;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_TRUE(frameRateOverrides.empty());
}
@@ -2399,37 +2154,32 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
HWC_CONFIG_ID_120, config);
- auto layers = std::vector<LayerRequirement>{
- LayerRequirement{.ownerUid = 1234, .weight = 1.0f},
- LayerRequirement{.ownerUid = 5678, .weight = 1.0f},
- };
+ std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f},
+ {.ownerUid = 5678, .weight = 1.f}};
layers[0].name = "Test layer 1234";
- layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].desiredRefreshRate = 60_Hz;
layers[0].vote = LayerVoteType::ExplicitDefault;
layers[1].name = "Test layer 5678";
- layers[1].desiredRefreshRate = Fps(30.0f);
+ layers[1].desiredRefreshRate = 30_Hz;
layers[1].vote = LayerVoteType::ExplicitDefault;
- auto frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_EQ(2, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
ASSERT_EQ(1, frameRateOverrides.count(5678));
- ASSERT_EQ(30.0f, frameRateOverrides.at(5678).getValue());
+ ASSERT_EQ(30_Hz, frameRateOverrides.at(5678));
layers[1].vote = LayerVoteType::Heuristic;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
layers[1].ownerUid = 1234;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_TRUE(frameRateOverrides.empty());
}
@@ -2439,54 +2189,44 @@
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
HWC_CONFIG_ID_120, config);
- auto layers = std::vector<LayerRequirement>{
- LayerRequirement{.ownerUid = 1234, .weight = 1.0f},
- };
-
+ std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f}};
layers[0].name = "Test layer";
- layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].desiredRefreshRate = 60_Hz;
layers[0].vote = LayerVoteType::ExplicitDefault;
- auto frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true});
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
layers[0].vote = LayerVoteType::ExplicitExact;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true});
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
- ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
- frameRateOverrides =
- refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true});
ASSERT_TRUE(frameRateOverrides.empty());
}
} // namespace
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 0a8759d..df4a9c4 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wextra"
-
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -35,8 +31,7 @@
using testing::_;
using testing::AtLeast;
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
class RefreshRateStatsTest : public testing::Test {
protected:
@@ -88,54 +83,53 @@
}
namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
TEST_F(RefreshRateStatsTest, oneConfigTest) {
init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
- std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(1, times.size());
- EXPECT_NE(0u, times.count("ScreenOff"));
- // Setting up tests on mobile harness can be flaky with time passing, so testing for
- // exact time changes can result in flaxy numbers. To avoid that remember old
- // numbers to make sure the correct values are increasing in the next test.
- auto screenOff = times["ScreenOff"];
+ auto times = mRefreshRateStats->getTotalTimes();
+ ASSERT_TRUE(times.contains("ScreenOff"));
+ EXPECT_EQ(1u, times.size());
// Screen is off by default.
+ std::chrono::milliseconds screenOff = times.get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(0u, times.count("90.00fps"));
+
+ EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+ EXPECT_FALSE(times.contains("90.00 Hz"));
const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
mRefreshRateStats->setRefreshRate(config0Fps);
mRefreshRateStats->setPowerMode(PowerMode::ON);
- screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+ screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_EQ(1u, times.count("90.00fps"));
- EXPECT_LT(0, times["90.00fps"]);
+
+ EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+ ASSERT_TRUE(times.contains("90.00 Hz"));
+ EXPECT_LT(0ms, times.get("90.00 Hz")->get());
mRefreshRateStats->setPowerMode(PowerMode::DOZE);
- auto ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
+ const auto ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90.00fps"]);
+
+ EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+ EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
mRefreshRateStats->setRefreshRate(config0Fps);
- screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+ screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
+
// Because the power mode is not PowerMode::ON, switching the config
// does not update refresh rates that come from the config.
- EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90.00fps"]);
+ EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+ EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
}
TEST_F(RefreshRateStatsTest, twoConfigsTest) {
@@ -146,78 +140,81 @@
EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
- std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(1, times.size());
- EXPECT_NE(0u, times.count("ScreenOff"));
- // Setting up tests on mobile harness can be flaky with time passing, so testing for
- // exact time changes can result in flaxy numbers. To avoid that remember old
- // numbers to make sure the correct values are increasing in the next test.
- auto screenOff = times["ScreenOff"];
+ auto times = mRefreshRateStats->getTotalTimes();
+ ASSERT_TRUE(times.contains("ScreenOff"));
+ EXPECT_EQ(1u, times.size());
// Screen is off by default.
+ std::chrono::milliseconds screenOff = times.get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_LT(screenOff, times["ScreenOff"]);
+
+ EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+ EXPECT_FALSE(times.contains("60.00 Hz"));
+ EXPECT_FALSE(times.contains("90.00 Hz"));
const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_1).getFps();
mRefreshRateStats->setRefreshRate(config0Fps);
mRefreshRateStats->setPowerMode(PowerMode::ON);
- screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+ screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_EQ(1u, times.count("90.00fps"));
- EXPECT_LT(0, times["90.00fps"]);
+
+ EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+ ASSERT_TRUE(times.contains("90.00 Hz"));
+ EXPECT_LT(0ms, times.get("90.00 Hz")->get());
// When power mode is normal, time for configs updates.
mRefreshRateStats->setRefreshRate(config1Fps);
- auto ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
+ auto ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90.00fps"]);
- ASSERT_EQ(1u, times.count("60.00fps"));
- EXPECT_LT(0, times["60.00fps"]);
+
+ EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+ EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
+ ASSERT_TRUE(times.contains("60.00 Hz"));
+ EXPECT_LT(0ms, times.get("60.00 Hz")->get());
mRefreshRateStats->setRefreshRate(config0Fps);
- auto sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
+ auto sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_LT(ninety, times["90.00fps"]);
- EXPECT_EQ(sixty, times["60.00fps"]);
+
+ EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+ EXPECT_LT(ninety, times.get("90.00 Hz")->get());
+ EXPECT_EQ(sixty, times.get("60.00 Hz")->get());
mRefreshRateStats->setRefreshRate(config1Fps);
- ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
+ ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90.00fps"]);
- EXPECT_LT(sixty, times["60.00fps"]);
+
+ EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+ EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
+ EXPECT_LT(sixty, times.get("60.00 Hz")->get());
// Because the power mode is not PowerMode::ON, switching the config
// does not update refresh rates that come from the config.
mRefreshRateStats->setPowerMode(PowerMode::DOZE);
mRefreshRateStats->setRefreshRate(config0Fps);
- sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
+ sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90.00fps"]);
- EXPECT_EQ(sixty, times["60.00fps"]);
+
+ EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+ EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
+ EXPECT_EQ(sixty, times.get("60.00 Hz")->get());
mRefreshRateStats->setRefreshRate(config1Fps);
- screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+ screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90.00fps"]);
- EXPECT_EQ(sixty, times["60.00fps"]);
-}
-} // namespace
-} // namespace scheduler
-} // namespace android
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
+ EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+ EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
+ EXPECT_EQ(sixty, times.get("60.00 Hz")->get());
+}
+
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index e2b3993..599b235 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -54,13 +54,13 @@
const DisplayModePtr mode60 = DisplayMode::Builder(0)
.setId(DisplayModeId(0))
.setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(Fps(60.f).getPeriodNsecs())
+ .setVsyncPeriod((60_Hz).getPeriodNsecs())
.setGroup(0)
.build();
const DisplayModePtr mode120 = DisplayMode::Builder(1)
.setId(DisplayModeId(1))
.setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(Fps(120.f).getPeriodNsecs())
+ .setVsyncPeriod((120_Hz).getPeriodNsecs())
.setGroup(0)
.build();
@@ -217,17 +217,17 @@
}
TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
- EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 30ms));
- EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(90), 30ms));
- EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(Fps(120), 30ms));
+ EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 30ms));
+ EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(90_Hz, 30ms));
+ EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(120_Hz, 30ms));
- EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 40ms));
+ EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 40ms));
- EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 10ms));
+ EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms));
}
MATCHER(Is120Hz, "") {
- return arg.getFps().equalsWithMargin(Fps(120.f));
+ return isApproxEqual(arg.getFps(), 120_Hz);
}
TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 6c3b2fd..d021178 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -29,6 +29,7 @@
#include "Layer.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
+#include "FpsOps.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/MockEventThread.h"
@@ -96,12 +97,11 @@
*/
class SetFrameRateTest : public ::testing::TestWithParam<std::shared_ptr<LayerFactory>> {
protected:
- const FrameRate FRAME_RATE_VOTE1 = FrameRate(Fps(67.f), FrameRateCompatibility::Default);
- const FrameRate FRAME_RATE_VOTE2 =
- FrameRate(Fps(14.f), FrameRateCompatibility::ExactOrMultiple);
- const FrameRate FRAME_RATE_VOTE3 = FrameRate(Fps(99.f), FrameRateCompatibility::NoVote);
- const FrameRate FRAME_RATE_TREE = FrameRate(Fps(0.f), FrameRateCompatibility::NoVote);
- const FrameRate FRAME_RATE_NO_VOTE = FrameRate(Fps(0.f), FrameRateCompatibility::Default);
+ const FrameRate FRAME_RATE_VOTE1 = FrameRate(67_Hz, FrameRateCompatibility::Default);
+ const FrameRate FRAME_RATE_VOTE2 = FrameRate(14_Hz, FrameRateCompatibility::ExactOrMultiple);
+ const FrameRate FRAME_RATE_VOTE3 = FrameRate(99_Hz, FrameRateCompatibility::NoVote);
+ const FrameRate FRAME_RATE_TREE = FrameRate(Fps(), FrameRateCompatibility::NoVote);
+ const FrameRate FRAME_RATE_NO_VOTE = FrameRate(Fps(), FrameRateCompatibility::Default);
SetFrameRateTest();
@@ -122,8 +122,6 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- mFlinger.mutableUseFrameRateApi() = true;
-
setupScheduler();
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
@@ -172,9 +170,7 @@
}
namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
TEST_P(SetFrameRateTest, SetAndGet) {
EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
@@ -470,8 +466,8 @@
.mutableLayerHistory()
->summarize(*mFlinger.mutableScheduler().refreshRateConfigs(), 0);
ASSERT_EQ(2u, layerHistorySummary.size());
- EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[0].desiredRefreshRate));
- EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate));
+ EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[0].desiredRefreshRate);
+ EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[1].desiredRefreshRate);
}
TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index dd20d0d..8cca6af 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -289,7 +289,7 @@
}
static void setLayerDrawingParent(const sp<Layer>& layer, const sp<Layer>& drawingParent) {
- layer->mDrawingParent = drawingParent.get();
+ layer->mDrawingParent = drawingParent;
}
/* ------------------------------------------------------------------------
@@ -375,6 +375,7 @@
auto& getTransactionQueue() { return mFlinger->mTransactionQueue; }
auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
+ auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; }
auto setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
@@ -445,7 +446,6 @@
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; }
- auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
auto& mutableActiveDisplayToken() { return mFlinger->mActiveDisplayToken; }
auto fromHandle(const sp<IBinder>& handle) {
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 317cdf1..1487a96 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -64,16 +64,14 @@
#define LAYER_ID_0 0
#define LAYER_ID_1 1
#define UID_0 123
-#define REFRESH_RATE_0 61
-#define RENDER_RATE_0 31
#define REFRESH_RATE_BUCKET_0 60
#define RENDER_RATE_BUCKET_0 30
#define LAYER_ID_INVALID -1
#define NUM_LAYERS 1
#define NUM_LAYERS_INVALID "INVALID"
-const constexpr Fps kRefreshRate0 = Fps(static_cast<float>(REFRESH_RATE_0));
-const constexpr Fps kRenderRate0 = Fps(static_cast<float>(RENDER_RATE_0));
+const constexpr Fps kRefreshRate0 = 61_Hz;
+const constexpr Fps kRenderRate0 = 31_Hz;
static constexpr int32_t kGameMode = TimeStatsHelper::GameModeUnsupported;
enum InputCommand : int32_t {
@@ -1498,14 +1496,14 @@
EXPECT_THAT(result, HasSubstr(expectedResult)) << "failed for " << fps;
};
- verifyRefreshRateBucket(Fps(91.f), 90);
- verifyRefreshRateBucket(Fps(89.f), 90);
+ verifyRefreshRateBucket(91_Hz, 90);
+ verifyRefreshRateBucket(89_Hz, 90);
- verifyRefreshRateBucket(Fps(61.f), 60);
- verifyRefreshRateBucket(Fps(59.f), 60);
+ verifyRefreshRateBucket(61_Hz, 60);
+ verifyRefreshRateBucket(59_Hz, 60);
- verifyRefreshRateBucket(Fps(31.f), 30);
- verifyRefreshRateBucket(Fps(29.f), 30);
+ verifyRefreshRateBucket(31_Hz, 30);
+ verifyRefreshRateBucket(29_Hz, 30);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 05551b4..8caadfb 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -24,8 +24,8 @@
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
+#include <ui/MockFence.h>
#include <utils/String8.h>
-
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/MockEventThread.h"
@@ -74,6 +74,13 @@
EXPECT_CALL(*mVSyncTracker, currentPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*mFenceUnsignaled, getStatus())
+ .WillRepeatedly(Return(Fence::Status::Unsignaled));
+ EXPECT_CALL(*mFenceUnsignaled2, getStatus())
+ .WillRepeatedly(Return(Fence::Status::Unsignaled));
+ EXPECT_CALL(*mFenceSignaled, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled));
+ EXPECT_CALL(*mFenceSignaled2, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled));
+
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
@@ -88,6 +95,10 @@
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::VsyncController* mVsyncController = new mock::VsyncController();
mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker();
+ mock::MockFence* mFenceUnsignaled = new mock::MockFence();
+ mock::MockFence* mFenceSignaled = new mock::MockFence();
+ mock::MockFence* mFenceUnsignaled2 = new mock::MockFence();
+ mock::MockFence* mFenceSignaled2 = new mock::MockFence();
struct TransactionInfo {
Vector<ComposerState> states;
@@ -124,6 +135,15 @@
transaction.frameTimelineInfo = frameTimelineInfo;
}
+ void setupSingleWithComposer(TransactionInfo& transaction, uint32_t flags,
+ bool syncInputWindows, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo,
+ const Vector<ComposerState>* states) {
+ setupSingle(transaction, flags, syncInputWindows, desiredPresentTime, isAutoTimestamp,
+ frameTimelineInfo);
+ transaction.states = *states;
+ }
+
void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
@@ -245,6 +265,188 @@
EXPECT_EQ(0u, transactionQueue.size());
}
+ void Flush_removesUnsignaledFromTheQueue(Vector<ComposerState> state1,
+ Vector<ComposerState> state2,
+ bool updateApplyToken = true) {
+ ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+
+ TransactionInfo transactionA;
+ setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
+ /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
+ FrameTimelineInfo{}, &state1);
+
+ mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
+ transactionA.displays, transactionA.flags,
+ transactionA.applyToken, transactionA.inputWindowCommands,
+ transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
+ transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transactionA.id);
+
+ TransactionInfo transactionB;
+ if (updateApplyToken) {
+ transactionB.applyToken = sp<IBinder>();
+ }
+ setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
+ /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
+ FrameTimelineInfo{}, &state2);
+ mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
+ transactionB.displays, transactionB.flags,
+ transactionB.applyToken, transactionB.inputWindowCommands,
+ transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
+ transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transactionB.id);
+
+ mFlinger.flushTransactionQueues();
+ EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size());
+ }
+
+ void Flush_removesFromTheQueue(const Vector<ComposerState>& state) {
+ ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+
+ TransactionInfo transaction;
+ setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous,
+ /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
+ FrameTimelineInfo{}, &state);
+
+ mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+ transaction.displays, transaction.flags,
+ transaction.applyToken, transaction.inputWindowCommands,
+ transaction.desiredPresentTime, transaction.isAutoTimestamp,
+ transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transaction.id);
+
+ mFlinger.flushTransactionQueues();
+ EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(1u, mFlinger.getTransactionCommittedSignals().size());
+ }
+
+ void Flush_keepsInTheQueue(const Vector<ComposerState>& state) {
+ ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+
+ TransactionInfo transaction;
+ setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous,
+ /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
+ FrameTimelineInfo{}, &state);
+
+ mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+ transaction.displays, transaction.flags,
+ transaction.applyToken, transaction.inputWindowCommands,
+ transaction.desiredPresentTime, transaction.isAutoTimestamp,
+ transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transaction.id);
+
+ mFlinger.flushTransactionQueues();
+ EXPECT_EQ(1u, mFlinger.getPendingTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
+ }
+
+ void Flush_KeepsUnsignaledInTheQueue(const Vector<ComposerState>& state1,
+ const Vector<ComposerState>& state2,
+ bool updateApplyToken = true,
+ uint32_t pendingTransactionQueueSize = 1u) {
+ EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+ ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+ auto time = systemTime();
+ TransactionInfo transactionA;
+ TransactionInfo transactionB;
+ setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
+ /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
+ FrameTimelineInfo{}, &state1);
+ setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
+ /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
+ FrameTimelineInfo{}, &state2);
+ mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
+ transactionA.displays, transactionA.flags,
+ transactionA.applyToken, transactionA.inputWindowCommands,
+ transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
+ transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transactionA.id);
+ if (updateApplyToken) {
+ transactionB.applyToken = sp<IBinder>();
+ }
+ mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
+ transactionB.displays, transactionB.flags,
+ transactionB.applyToken, transactionB.inputWindowCommands,
+ transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
+ transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transactionB.id);
+
+ mFlinger.flushTransactionQueues();
+ EXPECT_EQ(pendingTransactionQueueSize, mFlinger.getPendingTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ }
+
+ void Flush_removesSignaledFromTheQueue(const Vector<ComposerState>& state1,
+ const Vector<ComposerState>& state2) {
+ ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+
+ auto time = systemTime();
+ TransactionInfo transactionA;
+ TransactionInfo transactionB;
+ setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
+ /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
+ FrameTimelineInfo{}, &state1);
+ setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
+ /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
+ FrameTimelineInfo{}, &state2);
+ mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
+ transactionA.displays, transactionA.flags,
+ transactionA.applyToken, transactionA.inputWindowCommands,
+ transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
+ transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transactionA.id);
+ mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
+ transactionB.displays, transactionB.flags,
+ transactionB.applyToken, transactionB.inputWindowCommands,
+ transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
+ transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transactionB.id);
+
+ mFlinger.flushTransactionQueues();
+ EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+ EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size());
+ }
+
+ static Vector<ComposerState> createComposerStateVector(const ComposerState& state1,
+ const ComposerState& state2) {
+ Vector<ComposerState> states;
+ states.push_back(state1);
+ states.push_back(state2);
+ return states;
+ }
+
+ static Vector<ComposerState> createComposerStateVector(const ComposerState& state) {
+ Vector<ComposerState> states;
+ states.push_back(state);
+ return states;
+ }
+
+ static ComposerState createComposerState(int layerId, sp<Fence> fence,
+ uint32_t stateFlags = layer_state_t::eBufferChanged) {
+ ComposerState composer_state;
+ composer_state.state.bufferData.acquireFence = std::move(fence);
+ composer_state.state.layerId = layerId;
+ composer_state.state.bufferData.flags = BufferData::BufferDataChange::fenceChanged;
+ composer_state.state.flags = stateFlags;
+ return composer_state;
+ }
+
bool mHasListenerCallbacks = false;
std::vector<ListenerCallbacks> mCallbacks;
int mTransactionNumber = 0;
@@ -327,4 +529,216 @@
auto ret = mFlinger.fromHandle(badHandle);
EXPECT_EQ(nullptr, ret.promote().get());
}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesSingleSignaledFromTheQueue_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_removesFromTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesSingleUnSignaledFromTheQueue_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_removesFromTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+}
+
+TEST_F(TransactionApplicationTest,
+ Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_keepsInTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceUnsignaled, layer_state_t::eCropChanged)));
+}
+
+TEST_F(TransactionApplicationTest,
+ Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_keepsInTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceUnsignaled,
+ layer_state_t::eCropChanged | layer_state_t::eBufferChanged)));
+}
+
+TEST_F(TransactionApplicationTest,
+ Flush_KeepsInTheQueueSameApplyTokenMultiState_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_keepsInTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
+ createComposerState(/*layerId*/ 1, mFenceSignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_MultipleStateTransaction_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_keepsInTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
+ createComposerState(/*layerId*/ 2, mFenceSignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_removesSignaledFromTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceSignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemoveSignaledWithUnsignaledIntact_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceSignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceUnsignaled)));
+ EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+}
+
+TEST_F(TransactionApplicationTest,
+ Flush_KeepsTransactionInTheQueueSameApplyToken_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceSignaled)),
+ /*updateApplyToken*/ false);
+ EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+}
+
+TEST_F(TransactionApplicationTest, Flush_KeepsTransactionInTheQueue_LatchUnsignaled_Auto) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
+ Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
+ /*updateApplyToken*/ true,
+ /*pendingTransactionQueueSize*/ 2u);
+ EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Disabled) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ Flush_removesFromTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_LatchUnsignaled_Disabled) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ Flush_keepsInTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueSameLayerId_LatchUnsignaled_Disabled) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ Flush_keepsInTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
+ createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueDifferentLayerId_LatchUnsignaled_Disabled) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ Flush_keepsInTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
+ createComposerState(/*layerId*/ 2, mFenceUnsignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Disabled) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ Flush_removesSignaledFromTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceSignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+}
+
+TEST_F(TransactionApplicationTest,
+ Flush_KeepInTheQueueDifferentApplyToken_LatchUnsignaled_Disabled) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceSignaled)));
+ EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+}
+
+TEST_F(TransactionApplicationTest, Flush_KeepInTheQueueSameApplyToken_LatchUnsignaled_Disabled) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceSignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
+ /*updateApplyToken*/ false);
+ EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+}
+
+TEST_F(TransactionApplicationTest, Flush_KeepInTheUnsignaledTheQueue_LatchUnsignaled_Disabled) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+ Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
+ /*updateApplyToken*/ false);
+ EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Always) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ Flush_removesFromTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueue_LatchUnsignaled_Always) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ Flush_removesFromTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueueSameLayerId_LatchUnsignaled_Always) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ Flush_removesFromTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
+ createComposerState(/*layerId*/ 1, mFenceSignaled)));
+}
+
+TEST_F(TransactionApplicationTest,
+ Flush_RemovesFromTheQueueDifferentLayerId_LatchUnsignaled_Always) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ Flush_removesFromTheQueue(
+ createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
+ createComposerState(/*layerId*/ 2, mFenceSignaled)));
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Always) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ Flush_removesSignaledFromTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceSignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+}
+
+TEST_F(TransactionApplicationTest,
+ Flush_RemovesFromTheQueueDifferentApplyToken_LatchUnsignaled_Always) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1, mFenceSignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2,
+ mFenceUnsignaled)));
+}
+
+TEST_F(TransactionApplicationTest,
+ Flush_RemovesUnsignaledFromTheQueueSameApplyToken_LatchUnsignaled_Always) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1,
+ mFenceUnsignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2, mFenceSignaled)),
+ /*updateApplyToken*/ false);
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesUnsignaledFromTheQueue_LatchUnsignaled_Always) {
+ SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+ Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
+ createComposerState(/*layerId*/ 1,
+ mFenceUnsignaled)),
+ createComposerStateVector(
+ createComposerState(/*layerId*/ 2,
+ mFenceUnsignaled)));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 2b5b7b5..bf69704 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -344,7 +344,7 @@
// Both the droppedSurfaceFrame and presentedSurfaceFrame should be in
// pendingJankClassifications.
EXPECT_EQ(2u, layer->mPendingJankClassifications.size());
- presentedSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+ presentedSurfaceFrame->onPresent(20, JankType::None, 90_Hz,
/*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0);
layer->releasePendingBuffer(25);
@@ -462,10 +462,10 @@
// BufferlessSurfaceFrames are immediately set to presented and added to the DisplayFrame.
// Since we don't have access to DisplayFrame here, trigger an onPresent directly.
for (auto& surfaceFrame : bufferlessSurfaceFrames) {
- surfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+ surfaceFrame->onPresent(20, JankType::None, 90_Hz,
/*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0);
}
- presentedBufferSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+ presentedBufferSurfaceFrame->onPresent(20, JankType::None, 90_Hz,
/*displayDeadlineDelta*/ 0,
/*displayPresentDelta*/ 0);
diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
index 41a4d30..21ee071 100644
--- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
@@ -44,7 +44,7 @@
class WorkDurationTest : public testing::Test {
protected:
WorkDurationTest()
- : mWorkDuration(Fps(60.0f), 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
+ : mWorkDuration(60_Hz, 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
21'000'000, 1234) {}
~WorkDurationTest() = default;
@@ -56,9 +56,9 @@
* Test cases
*/
TEST_F(WorkDurationTest, getConfigsForRefreshRate_60Hz) {
- mWorkDuration.setRefreshRateFps(Fps(60.0f));
+ mWorkDuration.setRefreshRateFps(60_Hz);
auto currentOffsets = mWorkDuration.getCurrentConfigs();
- auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(60.0f));
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(60_Hz);
EXPECT_EQ(currentOffsets, offsets);
EXPECT_EQ(offsets.late.sfOffset, 6'166'667);
@@ -81,9 +81,9 @@
}
TEST_F(WorkDurationTest, getConfigsForRefreshRate_90Hz) {
- mWorkDuration.setRefreshRateFps(Fps(90.0f));
+ mWorkDuration.setRefreshRateFps(90_Hz);
auto currentOffsets = mWorkDuration.getCurrentConfigs();
- auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(90.0f));
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(90_Hz);
EXPECT_EQ(currentOffsets, offsets);
EXPECT_EQ(offsets.late.sfOffset, 611'111);
@@ -106,7 +106,7 @@
}
TEST_F(WorkDurationTest, getConfigsForRefreshRate_DefaultOffsets) {
- TestableWorkDuration phaseOffsetsWithDefaultValues(Fps(60.0f), -1, -1, -1, -1, -1, -1, 0);
+ TestableWorkDuration phaseOffsetsWithDefaultValues(60_Hz, -1, -1, -1, -1, -1, -1, 0);
auto validateOffsets = [](const auto& offsets, std::chrono::nanoseconds vsyncPeriod) {
EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
@@ -138,12 +138,12 @@
validateOffsets(offsets, std::chrono::nanoseconds(refreshRate.getPeriodNsecs()));
};
- testForRefreshRate(Fps(90.0f));
- testForRefreshRate(Fps(60.0f));
+ testForRefreshRate(90_Hz);
+ testForRefreshRate(60_Hz);
}
TEST_F(WorkDurationTest, getConfigsForRefreshRate_unknownRefreshRate) {
- auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(14.7f));
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(14.7_Hz);
EXPECT_EQ(offsets.late.sfOffset, 57'527'208);
EXPECT_EQ(offsets.late.appOffset, 37'027'208);
@@ -181,13 +181,12 @@
std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
nsecs_t thresholdForNextVsync, nsecs_t hwcMinWorkDuration)
- : impl::PhaseOffsets(Fps(60.0f), vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs,
- earlySfOffsetNs, earlyGpuSfOffsetNs, earlyAppOffsetNs,
- earlyGpuAppOffsetNs, highFpsVsyncPhaseOffsetNs,
- highFpsSfVSyncPhaseOffsetNs, highFpsEarlySfOffsetNs,
- highFpsEarlyGpuSfOffsetNs, highFpsEarlyAppOffsetNs,
- highFpsEarlyGpuAppOffsetNs, thresholdForNextVsync,
- hwcMinWorkDuration) {}
+ : impl::PhaseOffsets(60_Hz, vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs, earlySfOffsetNs,
+ earlyGpuSfOffsetNs, earlyAppOffsetNs, earlyGpuAppOffsetNs,
+ highFpsVsyncPhaseOffsetNs, highFpsSfVSyncPhaseOffsetNs,
+ highFpsEarlySfOffsetNs, highFpsEarlyGpuSfOffsetNs,
+ highFpsEarlyAppOffsetNs, highFpsEarlyGpuAppOffsetNs,
+ thresholdForNextVsync, hwcMinWorkDuration) {}
};
class PhaseOffsetsTest : public testing::Test {
@@ -201,7 +200,7 @@
};
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_unknownRefreshRate) {
- auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(14.7f));
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(14.7_Hz);
EXPECT_EQ(offsets.late.sfOffset, 6'000'000);
EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -223,7 +222,7 @@
}
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_60Hz) {
- auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(60.0f));
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(60_Hz);
EXPECT_EQ(offsets.late.sfOffset, 6'000'000);
EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -245,7 +244,7 @@
}
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_90Hz) {
- auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(90.0f));
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(90_Hz);
EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -269,7 +268,7 @@
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_60Hz) {
TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {}, 2'000'000,
1'000'000, {}, {}, {}, {}, 10'000'000, 1234};
- auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(60.0f));
+ auto offsets = phaseOffsets.getConfigsForRefreshRate(60_Hz);
EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
EXPECT_EQ(offsets.late.appOffset, 1'000'000);
@@ -293,7 +292,7 @@
TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_90Hz) {
TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {}, 2'000'000,
1'000'000, {}, {}, {}, {}, 10'000'000, 1234};
- auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(90.0f));
+ auto offsets = phaseOffsets.getConfigsForRefreshRate(90_Hz);
EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
EXPECT_EQ(offsets.late.appOffset, 2'000'000);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 159bdf1..23b849a 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -27,11 +27,21 @@
PowerAdvisor();
~PowerAdvisor() override;
- MOCK_METHOD0(init, void());
- MOCK_METHOD0(onBootFinished, void());
- MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
- MOCK_METHOD0(isUsingExpensiveRendering, bool());
- MOCK_METHOD0(notifyDisplayUpdateImminent, void());
+ MOCK_METHOD(void, init, (), (override));
+ MOCK_METHOD(void, onBootFinished, (), (override));
+ MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected),
+ (override));
+ MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override));
+ MOCK_METHOD(void, notifyDisplayUpdateImminent, (), (override));
+ MOCK_METHOD(bool, usePowerHintSession, (), (override));
+ MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
+ MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
+ MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
+ MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
+ (override));
+ MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
+ (override));
+ MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
};
} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index ddaa5a1..cae7684 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -175,6 +175,11 @@
void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
+ void expectSize(uint32_t width, uint32_t height) {
+ EXPECT_EQ(width, mOutBuffer->getWidth());
+ EXPECT_EQ(height, mOutBuffer->getHeight());
+ }
+
explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
if (mOutBuffer) {
mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index a375808..63ecaec 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -402,12 +402,21 @@
auto primitiveIdx = static_cast<size_t>(primitive);
if (primitiveIdx >= durations.size()) {
// Safety check, should not happen if enum_range is correct.
+ ALOGE("Supported primitive %zu is outside range [0,%zu), skipping load duration",
+ primitiveIdx, durations.size());
continue;
}
int32_t duration = 0;
- auto status = getHal()->getPrimitiveDuration(primitive, &duration);
- if (!status.isOk()) {
- return HalResult<std::vector<milliseconds>>::failed(status.toString8().c_str());
+ auto result = getHal()->getPrimitiveDuration(primitive, &duration);
+ auto halResult = HalResult<int32_t>::fromStatus(result, duration);
+ if (halResult.isUnsupported()) {
+ // Should not happen, supported primitives should always support requesting duration.
+ ALOGE("Supported primitive %zu returned unsupported for getPrimitiveDuration",
+ primitiveIdx);
+ }
+ if (halResult.isFailed()) {
+ // Fail entire request if one request has failed.
+ return HalResult<std::vector<milliseconds>>::failed(result.toString8().c_str());
}
durations[primitiveIdx] = milliseconds(duration);
}
diff --git a/services/vibratorservice/VibratorManagerHalController.cpp b/services/vibratorservice/VibratorManagerHalController.cpp
index 6bf6581..0df0bfa 100644
--- a/services/vibratorservice/VibratorManagerHalController.cpp
+++ b/services/vibratorservice/VibratorManagerHalController.cpp
@@ -45,7 +45,7 @@
template <typename T>
HalResult<T> ManagerHalController::processHalResult(HalResult<T> result, const char* functionName) {
if (result.isFailed()) {
- ALOGE("%s failed: %s", functionName, result.errorMessage());
+ ALOGE("VibratorManager HAL %s failed: %s", functionName, result.errorMessage());
std::lock_guard<std::mutex> lock(mConnectedHalMutex);
mConnectedHal->tryReconnect();
}
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index 6c31e2b..6b73d17 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -103,7 +103,7 @@
for (int i = 0; i < MAX_RETRIES; i++) {
T result = halFn(hal.get());
- if (result.checkAndLogFailure(functionName)) {
+ if (result.isFailedLogged(functionName)) {
tryReconnect();
} else {
return result;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 68d6647..d2cc9ad 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -69,9 +69,9 @@
bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
bool isUnsupported() const { return mUnsupported; }
const char* errorMessage() const { return mErrorMessage.c_str(); }
- bool checkAndLogFailure(const char* functionName) const {
+ bool isFailedLogged(const char* functionNameForLogging) const {
if (isFailed()) {
- ALOGE("%s failed: %s", functionName, errorMessage());
+ ALOGE("Vibrator HAL %s failed: %s", functionNameForLogging, errorMessage());
return true;
}
return false;
@@ -107,9 +107,9 @@
bool isFailed() const { return !mUnsupported && mFailed; }
bool isUnsupported() const { return mUnsupported; }
const char* errorMessage() const { return mErrorMessage.c_str(); }
- bool checkAndLogFailure(const char* functionName) const {
+ bool isFailedLogged(const char* functionNameForLogging) const {
if (isFailed()) {
- ALOGE("%s failed: %s", functionName, errorMessage());
+ ALOGE("Vibrator HAL %s failed: %s", functionNameForLogging, errorMessage());
return true;
}
return false;
@@ -192,21 +192,21 @@
const HalResult<float> qFactor;
const HalResult<std::vector<float>> maxAmplitudes;
- bool checkAndLogFailure(const char*) const {
- return capabilities.checkAndLogFailure("getCapabilities") ||
- supportedEffects.checkAndLogFailure("getSupportedEffects") ||
- supportedBraking.checkAndLogFailure("getSupportedBraking") ||
- supportedPrimitives.checkAndLogFailure("getSupportedPrimitives") ||
- primitiveDurations.checkAndLogFailure("getPrimitiveDuration") ||
- primitiveDelayMax.checkAndLogFailure("getPrimitiveDelayMax") ||
- pwlePrimitiveDurationMax.checkAndLogFailure("getPwlePrimitiveDurationMax") ||
- compositionSizeMax.checkAndLogFailure("getCompositionSizeMax") ||
- pwleSizeMax.checkAndLogFailure("getPwleSizeMax") ||
- minFrequency.checkAndLogFailure("getMinFrequency") ||
- resonantFrequency.checkAndLogFailure("getResonantFrequency") ||
- frequencyResolution.checkAndLogFailure("getFrequencyResolution") ||
- qFactor.checkAndLogFailure("getQFactor") ||
- maxAmplitudes.checkAndLogFailure("getMaxAmplitudes");
+ bool isFailedLogged(const char*) const {
+ return capabilities.isFailedLogged("getCapabilities") ||
+ supportedEffects.isFailedLogged("getSupportedEffects") ||
+ supportedBraking.isFailedLogged("getSupportedBraking") ||
+ supportedPrimitives.isFailedLogged("getSupportedPrimitives") ||
+ primitiveDurations.isFailedLogged("getPrimitiveDuration") ||
+ primitiveDelayMax.isFailedLogged("getPrimitiveDelayMax") ||
+ pwlePrimitiveDurationMax.isFailedLogged("getPwlePrimitiveDurationMax") ||
+ compositionSizeMax.isFailedLogged("getCompositionSizeMax") ||
+ pwleSizeMax.isFailedLogged("getPwleSizeMax") ||
+ minFrequency.isFailedLogged("getMinFrequency") ||
+ resonantFrequency.isFailedLogged("getResonantFrequency") ||
+ frequencyResolution.isFailedLogged("getFrequencyResolution") ||
+ qFactor.isFailedLogged("getQFactor") ||
+ maxAmplitudes.isFailedLogged("getMaxAmplitudes");
}
};
diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc
index 0de0f9e..1612743 100644
--- a/services/vr/virtual_touchpad/virtual_touchpad.rc
+++ b/services/vr/virtual_touchpad/virtual_touchpad.rc
@@ -2,4 +2,4 @@
class core
user system
group system input uhid
- writepid /dev/cpuset/system/tasks
+ task_profiles VrServiceCapacityNormal
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3ed3eba..e89a49b 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -736,7 +736,8 @@
// We must support R8G8B8A8
std::vector<VkSurfaceFormatKHR> all_formats = {
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
- {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+ {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+ {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT}};
if (wide_color_support) {
all_formats.emplace_back(VkSurfaceFormatKHR{