Merge "Use constexpr in VelocityTracker"
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..157d259 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;
}
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/Android.bp b/cmds/service/Android.bp
index 3e8e3f6..21ac11b 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -52,3 +52,21 @@
"-Werror",
],
}
+
+cc_binary_host {
+ name: "aservice",
+
+ srcs: ["service.cpp"],
+
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libbinder",
+ ],
+
+ cflags: [
+ "-DXP_UNIX",
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 18b6b58..fdbe85b 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -50,6 +50,7 @@
{
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();
@@ -76,6 +77,9 @@
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)
@@ -87,7 +91,7 @@
wantsUsage = true;
break;
default:
- aerr << "service: Unknown option -" << ic << endl;
+ aerr << prog_name << ": Unknown option -" << ic << endl;
wantsUsage = true;
result = 10;
break;
@@ -96,10 +100,13 @@
#ifdef VENDORSERVICES
ProcessState::initWithDriver("/dev/vndbinder");
#endif
+#ifndef __ANDROID__
+ setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingThreads = 1}));
+#endif
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;
}
@@ -113,7 +120,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;
}
@@ -138,6 +145,7 @@
int32_t code = atoi(argv[optind++]);
if (service != nullptr && ifName.size() > 0) {
Parcel data, reply;
+ data.markForBinder(service);
// the interface name is first
data.writeInterfaceToken(ifName);
@@ -147,7 +155,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;
@@ -156,7 +164,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;
@@ -165,7 +173,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;
@@ -174,7 +182,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;
@@ -183,7 +191,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;
@@ -195,7 +203,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;
@@ -203,7 +211,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;
@@ -212,7 +220,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;
@@ -221,7 +229,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;
@@ -229,13 +238,14 @@
int afd = ashmem_create_region("test", statbuf.st_size);
void* ptr = mmap(NULL, statbuf.st_size,
PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
- read(fd, ptr, statbuf.st_size);
+ (void)read(fd, ptr, statbuf.st_size);
close(fd);
data.writeFileDescriptor(afd, true /* take ownership */);
} 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;
@@ -322,7 +332,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;
@@ -332,44 +342,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/data/etc/Android.bp b/data/etc/Android.bp
index 235990a..5fe4ea1 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -185,6 +185,12 @@
}
prebuilt_etc {
+ name: "android.hardware.wifi.passpoint.prebuilt.xml",
+ src: "android.hardware.wifi.passpoint.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.software.device_id_attestation.prebuilt.xml",
src: "android.software.device_id_attestation.xml",
defaults: ["frameworks_native_data_etc_defaults"],
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/binder/Android.bp b/libs/binder/Android.bp
index 89a31c5..56cf76f 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -153,10 +153,6 @@
export_aidl_headers: true,
},
- // TODO(b/142684679): for com.android.media which is compiled
- // as vendor and used as system code.
- use_apex_name_macro: true,
-
cflags: [
"-Wall",
"-Wextra",
@@ -303,6 +299,14 @@
"aidl/android/content/pm/ApexStagedEvent.aidl",
"aidl/android/content/pm/StagedApexInfo.aidl",
],
+ backend: {
+ rust: {
+ apex_available: [
+ "com.android.virt",
+ ],
+ enabled: true,
+ },
+ },
}
aidl_interface {
@@ -327,6 +331,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/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index aff9e0d..81e61da 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -448,21 +448,27 @@
// on-device service manager.
class ServiceManagerHostShim : public ServiceManagerShim {
public:
- using ServiceManagerShim::ServiceManagerShim;
+ ServiceManagerHostShim(const sp<AidlServiceManager>& impl,
+ const RpcDelegateServiceManagerOptions& options)
+ : ServiceManagerShim(impl), mOptions(options) {}
// ServiceManagerShim::getService is based on checkService, so no need to override it.
sp<IBinder> checkService(const String16& name) const override {
- return getDeviceService({String8(name).c_str()});
+ return getDeviceService({String8(name).c_str()}, mOptions);
}
protected:
// Override realGetService for ServiceManagerShim::waitForService.
Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
- *_aidl_return = getDeviceService({"-g", name});
+ *_aidl_return = getDeviceService({"-g", name}, mOptions);
return Status::ok();
}
+
+private:
+ RpcDelegateServiceManagerOptions mOptions;
};
-sp<IServiceManager> createRpcDelegateServiceManager() {
- auto binder = getDeviceService({"manager"});
+sp<IServiceManager> createRpcDelegateServiceManager(
+ const RpcDelegateServiceManagerOptions& options) {
+ auto binder = getDeviceService({"manager"}, options);
if (binder == nullptr) {
ALOGE("getDeviceService(\"manager\") returns null");
return nullptr;
@@ -472,7 +478,7 @@
ALOGE("getDeviceService(\"manager\") returns non service manager");
return nullptr;
}
- return sp<ServiceManagerHostShim>::make(interface);
+ return sp<ServiceManagerHostShim>::make(interface, options);
}
#endif
diff --git a/libs/binder/OWNERS b/libs/binder/OWNERS
index 350994a..1c8bdea 100644
--- a/libs/binder/OWNERS
+++ b/libs/binder/OWNERS
@@ -1,5 +1,7 @@
+# Bug component: 32456
arve@google.com
ctate@google.com
hackbod@google.com
maco@google.com
smoreland@google.com
+tkjos@google.com
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 07555f6..181f405 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -98,9 +98,8 @@
BLOB_ASHMEM_MUTABLE = 2,
};
-static void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
-{
+static void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj,
+ const void* who) {
switch (obj.hdr.type) {
case BINDER_TYPE_BINDER:
if (obj.binder) {
@@ -117,13 +116,6 @@
return;
}
case BINDER_TYPE_FD: {
- if ((obj.cookie != 0) && (outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
- // If we own an ashmem fd, keep track of how much memory it refers to.
- int size = ashmem_get_size_region(obj.handle);
- if (size > 0) {
- *outAshmemSize += size;
- }
- }
return;
}
}
@@ -131,9 +123,8 @@
ALOGD("Invalid object type 0x%08x", obj.hdr.type);
}
-static void release_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
-{
+static void release_object(const sp<ProcessState>& proc, const flat_binder_object& obj,
+ const void* who) {
switch (obj.hdr.type) {
case BINDER_TYPE_BINDER:
if (obj.binder) {
@@ -151,16 +142,6 @@
}
case BINDER_TYPE_FD: {
if (obj.cookie != 0) { // owned
- if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
- int size = ashmem_get_size_region(obj.handle);
- if (size > 0) {
- // ashmem size might have changed since last time it was accounted for, e.g.
- // in acquire_object(). Value of *outAshmemSize is not critical since we are
- // releasing the object anyway. Check for integer overflow condition.
- *outAshmemSize -= std::min(*outAshmemSize, static_cast<size_t>(size));
- }
- }
-
close(obj.handle);
}
return;
@@ -430,8 +411,9 @@
status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
{
- if (parcel->isForRpc() != isForRpc()) {
- ALOGE("Cannot append Parcel of one format to another.");
+ if (mSession != parcel->mSession) {
+ ALOGE("Cannot append Parcel from one context to another. They may be different formats, "
+ "and objects are specific to a context.");
return BAD_TYPE;
}
@@ -512,7 +494,7 @@
flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(mData + off);
- acquire_object(proc, *flat, this, &mOpenAshmemSize);
+ acquire_object(proc, *flat, this);
if (flat->hdr.type == BINDER_TYPE_FD) {
// If this is a file descriptor, we need to dup it so the
@@ -566,6 +548,33 @@
return mHasFds;
}
+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;
+ if (__builtin_add_overflow(offset, len, &limit) || limit > mDataSize) {
+ return BAD_VALUE;
+ }
+ *result = false;
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ size_t pos = mObjects[i];
+ if (pos < offset) continue;
+ if (pos + sizeof(flat_binder_object) > offset + len) {
+ if (mObjectsSorted) break;
+ else continue;
+ }
+ const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + pos);
+ if (flat->hdr.type == BINDER_TYPE_FD) {
+ *result = true;
+ break;
+ }
+ }
+ return NO_ERROR;
+}
+
void Parcel::markSensitive() const
{
mDeallocZero = true;
@@ -1335,7 +1344,7 @@
// Need to write meta-data?
if (nullMetaData || val.binder != 0) {
mObjects[mObjectsSize] = mDataPos;
- acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
+ acquire_object(ProcessState::self(), val, this);
mObjectsSize++;
}
@@ -2225,7 +2234,7 @@
i--;
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(data+objects[i]);
- release_object(proc, *flat, this, &mOpenAshmemSize);
+ release_object(proc, *flat, this);
}
}
@@ -2242,7 +2251,7 @@
i--;
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(data+objects[i]);
- acquire_object(proc, *flat, this, &mOpenAshmemSize);
+ acquire_object(proc, *flat, this);
}
}
@@ -2447,7 +2456,7 @@
// will need to rescan because we may have lopped off the only FDs
mFdsKnown = false;
}
- release_object(proc, *flat, this, &mOpenAshmemSize);
+ release_object(proc, *flat, this);
}
if (objectsSize == 0) {
@@ -2540,7 +2549,6 @@
mAllowFds = true;
mDeallocZero = false;
mOwner = nullptr;
- mOpenAshmemSize = 0;
mWorkSourceRequestHeaderPosition = 0;
mRequestHeaderPresent = false;
@@ -2557,18 +2565,9 @@
}
}
-void Parcel::scanForFds() const
-{
- bool hasFds = false;
- for (size_t i=0; i<mObjectsSize; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
- if (flat->hdr.type == BINDER_TYPE_FD) {
- hasFds = true;
- break;
- }
- }
- mHasFds = hasFds;
+void Parcel::scanForFds() const {
+ status_t status = hasFileDescriptorsInRange(0, dataSize(), &mHasFds);
+ ALOGE_IF(status != NO_ERROR, "Error %d calling hasFileDescriptorsInRange()", status);
mFdsKnown = true;
}
@@ -2576,13 +2575,28 @@
{
// This used to return the size of all blobs that were written to ashmem, now we're returning
// the ashmem currently referenced by this Parcel, which should be equivalent.
- // TODO: Remove method once ABI can be changed.
- return mOpenAshmemSize;
+ // TODO(b/202029388): Remove method once ABI can be changed.
+ return getOpenAshmemSize();
}
size_t Parcel::getOpenAshmemSize() const
{
- return mOpenAshmemSize;
+ size_t openAshmemSize = 0;
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+
+ // cookie is compared against zero for historical reasons
+ // > obj.cookie = takeOwnership ? 1 : 0;
+ if (flat->hdr.type == BINDER_TYPE_FD && flat->cookie != 0 && ashmem_valid(flat->handle)) {
+ int size = ashmem_get_size_region(flat->handle);
+ if (__builtin_add_overflow(openAshmemSize, size, &openAshmemSize)) {
+ ALOGE("Overflow when computing ashmem size.");
+ return SIZE_MAX;
+ }
+ }
+ }
+ return openAshmemSize;
}
// --- Parcel::Blob ---
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 44b588b..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);
@@ -381,13 +388,25 @@
} while (server->mSessions.end() != server->mSessions.find(sessionId));
session = RpcSession::make();
- session->setMaxThreads(server->mMaxThreads);
+ 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 4465b8e..53c9b78 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -61,7 +61,7 @@
LOG_RPC_DETAIL("RpcSession destroyed %p", this);
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mThreadState.mIncomingConnections.size() != 0,
+ LOG_ALWAYS_FATAL_IF(mConnections.mIncoming.size() != 0,
"Should not be able to destroy a session with servers in use.");
}
@@ -76,20 +76,32 @@
return sp<RpcSession>::make(std::move(ctx));
}
-void RpcSession::setMaxThreads(size_t threads) {
+void RpcSession::setMaxIncomingThreads(size_t threads) {
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(!mThreadState.mOutgoingConnections.empty() ||
- !mThreadState.mIncomingConnections.empty(),
- "Must set max threads before setting up connections, but has %zu client(s) "
- "and %zu server(s)",
- mThreadState.mOutgoingConnections.size(),
- mThreadState.mIncomingConnections.size());
- mMaxThreads = threads;
+ LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
+ "Must set max incoming threads before setting up connections, but has %zu "
+ "client(s) and %zu server(s)",
+ mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+ mMaxIncomingThreads = threads;
}
-size_t RpcSession::getMaxThreads() {
+size_t RpcSession::getMaxIncomingThreads() {
std::lock_guard<std::mutex> _l(mMutex);
- return mMaxThreads;
+ return mMaxIncomingThreads;
+}
+
+void RpcSession::setMaxOutgoingThreads(size_t threads) {
+ std::lock_guard<std::mutex> _l(mMutex);
+ LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
+ "Must set max outgoing threads before setting up connections, but has %zu "
+ "client(s) and %zu server(s)",
+ mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+ mMaxOutgoingThreads = threads;
+}
+
+size_t RpcSession::getMaxOutgoingThreads() {
+ std::lock_guard<std::mutex> _l(mMutex);
+ return mMaxOutgoingThreads;
}
bool RpcSession::setProtocolVersion(uint32_t version) {
@@ -197,7 +209,7 @@
LOG_ALWAYS_FATAL_IF(mShutdownListener == nullptr, "Shutdown listener not installed");
mShutdownListener->waitForShutdown(_l, sp<RpcSession>::fromExisting(this));
- LOG_ALWAYS_FATAL_IF(!mThreadState.mThreads.empty(), "Shutdown failed");
+ LOG_ALWAYS_FATAL_IF(!mConnections.mThreads.empty(), "Shutdown failed");
}
_l.unlock();
@@ -263,11 +275,11 @@
void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock,
const sp<RpcSession>& session) {
- while (session->mThreadState.mIncomingConnections.size() > 0) {
+ while (session->mConnections.mIncoming.size() > 0) {
if (std::cv_status::timeout == mCv.wait_for(lock, std::chrono::seconds(1))) {
ALOGE("Waiting for RpcSession to shut down (1s w/o progress): %zu incoming connections "
"still.",
- session->mThreadState.mIncomingConnections.size());
+ session->mConnections.mIncoming.size());
}
}
}
@@ -277,7 +289,7 @@
{
std::lock_guard<std::mutex> _l(mMutex);
- mThreadState.mThreads[thread.get_id()] = std::move(thread);
+ mConnections.mThreads[thread.get_id()] = std::move(thread);
}
}
@@ -380,10 +392,10 @@
sp<RpcSession::EventListener> listener;
{
std::lock_guard<std::mutex> _l(session->mMutex);
- auto it = session->mThreadState.mThreads.find(std::this_thread::get_id());
- LOG_ALWAYS_FATAL_IF(it == session->mThreadState.mThreads.end());
+ auto it = session->mConnections.mThreads.find(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(it == session->mConnections.mThreads.end());
it->second.detach();
- session->mThreadState.mThreads.erase(it);
+ session->mConnections.mThreads.erase(it);
listener = session->mEventListener.promote();
}
@@ -414,9 +426,9 @@
bool incoming)>& connectAndInit) {
{
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mThreadState.mOutgoingConnections.size() != 0,
+ LOG_ALWAYS_FATAL_IF(mConnections.mOutgoing.size() != 0,
"Must only setup session once, but already has %zu clients",
- mThreadState.mOutgoingConnections.size());
+ mConnections.mOutgoing.size());
}
if (auto status = initShutdownTrigger(); status != OK) return status;
@@ -439,7 +451,7 @@
// downgrade again
mProtocolVersion = oldProtocolVersion;
- mThreadState = {};
+ mConnections = {};
});
if (status_t status = connectAndInit({}, false /*incoming*/); status != OK) return status;
@@ -475,6 +487,12 @@
return status;
}
+ size_t outgoingThreads = std::min(numThreadsAvailable, mMaxOutgoingThreads);
+ ALOGI_IF(outgoingThreads != numThreadsAvailable,
+ "Server hints client to start %zu outgoing threads, but client will only start %zu "
+ "because it is preconfigured to start at most %zu outgoing threads.",
+ numThreadsAvailable, outgoingThreads, mMaxOutgoingThreads);
+
// TODO(b/189955605): we should add additional sessions dynamically
// instead of all at once - the other side should be responsible for setting
// up additional connections. We need to create at least one (unless 0 are
@@ -482,11 +500,14 @@
// any requests at all.
// we've already setup one client
- for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
+ LOG_RPC_DETAIL("RpcSession::setupClient() instantiating %zu outgoing (server max: %zu) and %zu "
+ "incoming threads",
+ outgoingThreads, numThreadsAvailable, mMaxIncomingThreads);
+ for (size_t i = 0; i + 1 < outgoingThreads; i++) {
if (status_t status = connectAndInit(mId, false /*incoming*/); status != OK) return status;
}
- for (size_t i = 0; i < mMaxThreads; i++) {
+ for (size_t i = 0; i < mMaxIncomingThreads; i++) {
if (status_t status = connectAndInit(mId, true /*incoming*/); status != OK) return status;
}
@@ -662,12 +683,13 @@
std::lock_guard<std::mutex> _l(mMutex);
connection->rpcTransport = std::move(rpcTransport);
connection->exclusiveTid = gettid();
- mThreadState.mOutgoingConnections.push_back(connection);
+ mConnections.mOutgoing.push_back(connection);
}
status_t status = OK;
if (init) {
- mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+ status =
+ mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
}
{
@@ -679,7 +701,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);
@@ -692,6 +715,7 @@
mId = sessionId;
mForServer = server;
mEventListener = eventListener;
+ mSessionSpecificRootObject = sessionSpecificRoot;
return true;
}
@@ -699,9 +723,9 @@
std::unique_ptr<RpcTransport> rpcTransport) {
std::lock_guard<std::mutex> _l(mMutex);
- if (mThreadState.mIncomingConnections.size() >= mMaxThreads) {
+ if (mConnections.mIncoming.size() >= mMaxIncomingThreads) {
ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
- mThreadState.mIncomingConnections.size(), mMaxThreads);
+ mConnections.mIncoming.size(), mMaxIncomingThreads);
return nullptr;
}
@@ -709,7 +733,7 @@
// happens when new connections are still being established as part of a
// very short-lived session which shuts down after it already started
// accepting new connections.
- if (mThreadState.mIncomingConnections.size() < mThreadState.mMaxIncomingConnections) {
+ if (mConnections.mIncoming.size() < mConnections.mMaxIncoming) {
return nullptr;
}
@@ -717,19 +741,19 @@
session->rpcTransport = std::move(rpcTransport);
session->exclusiveTid = gettid();
- mThreadState.mIncomingConnections.push_back(session);
- mThreadState.mMaxIncomingConnections = mThreadState.mIncomingConnections.size();
+ mConnections.mIncoming.push_back(session);
+ mConnections.mMaxIncoming = mConnections.mIncoming.size();
return session;
}
bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
std::unique_lock<std::mutex> _l(mMutex);
- if (auto it = std::find(mThreadState.mIncomingConnections.begin(),
- mThreadState.mIncomingConnections.end(), connection);
- it != mThreadState.mIncomingConnections.end()) {
- mThreadState.mIncomingConnections.erase(it);
- if (mThreadState.mIncomingConnections.size() == 0) {
+ if (auto it =
+ std::find(mConnections.mIncoming.begin(), mConnections.mIncoming.end(), connection);
+ it != mConnections.mIncoming.end()) {
+ mConnections.mIncoming.erase(it);
+ if (mConnections.mIncoming.size() == 0) {
sp<EventListener> listener = mEventListener.promote();
if (listener) {
_l.unlock();
@@ -754,7 +778,7 @@
pid_t tid = gettid();
std::unique_lock<std::mutex> _l(session->mMutex);
- session->mThreadState.mWaitingThreads++;
+ session->mConnections.mWaitingThreads++;
while (true) {
sp<RpcConnection> exclusive;
sp<RpcConnection> available;
@@ -762,11 +786,11 @@
// CHECK FOR DEDICATED CLIENT SOCKET
//
// A server/looper should always use a dedicated connection if available
- findConnection(tid, &exclusive, &available, session->mThreadState.mOutgoingConnections,
- session->mThreadState.mOutgoingConnectionsOffset);
+ findConnection(tid, &exclusive, &available, session->mConnections.mOutgoing,
+ session->mConnections.mOutgoingOffset);
// WARNING: this assumes a server cannot request its client to send
- // a transaction, as mIncomingConnections is excluded below.
+ // a transaction, as mIncoming is excluded below.
//
// Imagine we have more than one thread in play, and a single thread
// sends a synchronous, then an asynchronous command. Imagine the
@@ -776,9 +800,8 @@
// command. So, we move to considering the second available thread
// for subsequent calls.
if (use == ConnectionUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
- session->mThreadState.mOutgoingConnectionsOffset =
- (session->mThreadState.mOutgoingConnectionsOffset + 1) %
- session->mThreadState.mOutgoingConnections.size();
+ session->mConnections.mOutgoingOffset = (session->mConnections.mOutgoingOffset + 1) %
+ session->mConnections.mOutgoing.size();
}
// USE SERVING SOCKET (e.g. nested transaction)
@@ -786,7 +809,7 @@
sp<RpcConnection> exclusiveIncoming;
// server connections are always assigned to a thread
findConnection(tid, &exclusiveIncoming, nullptr /*available*/,
- session->mThreadState.mIncomingConnections, 0 /* index hint */);
+ session->mConnections.mIncoming, 0 /* index hint */);
// asynchronous calls cannot be nested, we currently allow ref count
// calls to be nested (so that you can use this without having extra
@@ -815,20 +838,20 @@
break;
}
- if (session->mThreadState.mOutgoingConnections.size() == 0) {
+ if (session->mConnections.mOutgoing.size() == 0) {
ALOGE("Session has no client connections. This is required for an RPC server to make "
"any non-nested (e.g. oneway or on another thread) calls. Use: %d. Server "
"connections: %zu",
- static_cast<int>(use), session->mThreadState.mIncomingConnections.size());
+ static_cast<int>(use), session->mConnections.mIncoming.size());
return WOULD_BLOCK;
}
LOG_RPC_DETAIL("No available connections (have %zu clients and %zu servers). Waiting...",
- session->mThreadState.mOutgoingConnections.size(),
- session->mThreadState.mIncomingConnections.size());
+ session->mConnections.mOutgoing.size(),
+ session->mConnections.mIncoming.size());
session->mAvailableConnectionCv.wait(_l);
}
- session->mThreadState.mWaitingThreads--;
+ session->mConnections.mWaitingThreads--;
return OK;
}
@@ -867,7 +890,7 @@
if (!mReentrant && mConnection != nullptr) {
std::unique_lock<std::mutex> _l(mSession->mMutex);
mConnection->exclusiveTid = std::nullopt;
- if (mSession->mThreadState.mWaitingThreads > 0) {
+ if (mSession->mConnections.mWaitingThreads > 0) {
_l.unlock();
mSession->mAvailableConnectionCv.notify_one();
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index ef62f20..09b3d68 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -855,7 +855,7 @@
switch (transaction->code) {
case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
- replyStatus = reply.writeInt32(session->getMaxThreads());
+ replyStatus = reply.writeInt32(session->getMaxIncomingThreads());
break;
}
case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
@@ -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/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 27cc563..194254a 100644
--- a/libs/binder/ServiceManagerHost.cpp
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -124,7 +124,8 @@
} // namespace
-sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs) {
+sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs,
+ const RpcDelegateServiceManagerOptions& options) {
std::vector<std::string> prefix{"adb", "shell", "servicedispatcher"};
serviceDispatcherArgs.insert(serviceDispatcherArgs.begin(), prefix.begin(), prefix.end());
@@ -158,6 +159,10 @@
LOG_ALWAYS_FATAL_IF(!forwardResult->hostPort().has_value());
auto rpcSession = RpcSession::make();
+ if (options.maxOutgoingThreads.has_value()) {
+ rpcSession->setMaxOutgoingThreads(*options.maxOutgoingThreads);
+ }
+
if (status_t status = rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort());
status != OK) {
ALOGE("Unable to set up inet client on host port %u: %s", *forwardResult->hostPort(),
diff --git a/libs/binder/ServiceManagerHost.h b/libs/binder/ServiceManagerHost.h
index e59724c..c5310da 100644
--- a/libs/binder/ServiceManagerHost.h
+++ b/libs/binder/ServiceManagerHost.h
@@ -21,11 +21,14 @@
namespace android {
+struct RpcDelegateServiceManagerOptions;
+
// Get a service on device by running servicedispatcher with the given args, e.g.
// getDeviceService({"foo"});
// Return nullptr on any error.
// When the returned binder object is destroyed, remove adb forwarding and kills
// the long-running servicedispatcher process.
-sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs);
+sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs,
+ const RpcDelegateServiceManagerOptions& options);
} // namespace android
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index d71f496..7c99f76 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -144,5 +144,5 @@
* Get information of APEX which is staged ready for installation.
* Returns null if no such APEX is found.
*/
- StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
+ @nullable StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index a48075d..240e3c2 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -188,7 +188,16 @@
// // ...
// }
// Resources are cleaned up when the object is destroyed.
-sp<IServiceManager> createRpcDelegateServiceManager();
+//
+// For each returned binder object, at most |maxOutgoingThreads| outgoing threads are instantiated.
+// Hence, only |maxOutgoingThreads| calls can be made simultaneously. Additional calls are blocked
+// if there are |maxOutgoingThreads| ongoing calls. See RpcSession::setMaxOutgoingThreads.
+// If |maxOutgoingThreads| is not set, default is |RpcSession::kDefaultMaxOutgoingThreads|.
+struct RpcDelegateServiceManagerOptions {
+ std::optional<size_t> maxOutgoingThreads;
+};
+sp<IServiceManager> createRpcDelegateServiceManager(
+ const RpcDelegateServiceManagerOptions& options);
#endif
} // namespace android
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index fd8ac62..d90e803 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -87,6 +87,7 @@
void restoreAllowFds(bool lastValue);
bool hasFileDescriptors() 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.
@@ -1141,6 +1142,7 @@
release_func mOwner;
sp<RpcSession> mSession;
+ size_t mReserved;
class Blob {
public:
@@ -1225,13 +1227,19 @@
inline void* data() { return mData; }
};
-private:
- size_t mOpenAshmemSize;
-
-public:
- // TODO: Remove once ABI can be changed.
- size_t getBlobAshmemSize() const;
+ /**
+ * Returns the total amount of ashmem memory owned by this object.
+ *
+ * Note: for historical reasons, this does not include ashmem memory which
+ * is referenced by this Parcel, but which this parcel doesn't own (e.g.
+ * writeFileDescriptor is called without 'takeOwnership' true).
+ */
size_t getOpenAshmemSize() const;
+
+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 19888b7..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;
@@ -50,6 +46,8 @@
*/
class RpcSession final : public virtual RefBase {
public:
+ static constexpr size_t kDefaultMaxOutgoingThreads = 10;
+
// Create an RpcSession with default configuration (raw sockets).
static sp<RpcSession> make();
@@ -59,7 +57,7 @@
static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
/**
- * Set the maximum number of threads allowed to be made (for things like callbacks).
+ * Set the maximum number of incoming threads allowed to be made (for things like callbacks).
* By default, this is 0. This must be called before setting up this connection as a client.
* Server sessions will inherits this value from RpcServer.
*
@@ -68,8 +66,20 @@
*
* TODO(b/189955605): start these dynamically
*/
- void setMaxThreads(size_t threads);
- size_t getMaxThreads();
+ void setMaxIncomingThreads(size_t threads);
+ size_t getMaxIncomingThreads();
+
+ /**
+ * Set the maximum number of outgoing threads allowed to be made.
+ * By default, this is |kDefaultMaxOutgoingThreads|. This must be called before setting up this
+ * connection as a client.
+ *
+ * This limits the number of outgoing threads on top of the remote peer setting. This RpcSession
+ * will only instantiate |min(maxOutgoingThreads, remoteMaxThreads)| outgoing threads, where
+ * |remoteMaxThreads| can be retrieved from the remote peer via |getRemoteMaxThreads()|.
+ */
+ void setMaxOutgoingThreads(size_t threads);
+ size_t getMaxOutgoingThreads();
/**
* By default, the minimum of the supported versions of the client and the
@@ -126,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
@@ -206,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
@@ -242,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,
@@ -258,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; }
@@ -281,13 +292,13 @@
const std::unique_ptr<RpcTransportCtx> mCtx;
- // On the other side of a session, for each of mOutgoingConnections here, there should
- // be one of mIncomingConnections on the other side (and vice versa).
+ // On the other side of a session, for each of mOutgoing here, there should
+ // be one of mIncoming on the other side (and vice versa).
//
// For the simplest session, a single server with one client, you would
// have:
- // - the server has a single 'mIncomingConnections' and a thread listening on this
- // - the client has a single 'mOutgoingConnections' and makes calls to this
+ // - the server has a single 'mIncoming' and a thread listening on this
+ // - the client has a single 'mOutgoing' and makes calls to this
// - here, when the client makes a call, the server can call back into it
// (nested calls), but outside of this, the client will only ever read
// calls from the server when it makes a call itself.
@@ -299,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;
@@ -307,7 +322,8 @@
std::mutex mMutex; // for all below
- size_t mMaxThreads = 0;
+ size_t mMaxIncomingThreads = 0;
+ size_t mMaxOutgoingThreads = kDefaultMaxOutgoingThreads;
std::optional<uint32_t> mProtocolVersion;
std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
@@ -315,12 +331,12 @@
struct ThreadState {
size_t mWaitingThreads = 0;
// hint index into clients, ++ when sending an async transaction
- size_t mOutgoingConnectionsOffset = 0;
- std::vector<sp<RpcConnection>> mOutgoingConnections;
- size_t mMaxIncomingConnections = 0;
- std::vector<sp<RpcConnection>> mIncomingConnections;
+ size_t mOutgoingOffset = 0;
+ std::vector<sp<RpcConnection>> mOutgoing;
+ size_t mMaxIncoming = 0;
+ std::vector<sp<RpcConnection>> mIncoming;
std::map<std::thread::id, std::thread> mThreads;
- } mThreadState;
+ } mConnections;
};
} // namespace android
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/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 49c7b7c..81aa551 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -780,3 +780,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 563d011..2b18a0a 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -543,6 +543,28 @@
}
/**
+ * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_writeNullableStdVectorParcelableElement(AParcel* parcel,
+ 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));
+}
+
+/**
+ * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'.
+ */
+template <typename P>
+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));
+}
+
+/**
* Writes a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index'
* to 'parcel'.
*/
@@ -551,11 +573,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));
}
/**
@@ -567,15 +585,79 @@
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));
+}
+
+/**
+ * Writes an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index'
+ * to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeStdVectorParcelableElement<SpAIBinder>(AParcel* parcel,
+ const void* vectorData,
+ size_t index) {
+ const std::vector<SpAIBinder>* vector = static_cast<const std::vector<SpAIBinder>*>(vectorData);
+ return AParcel_writeRequiredStrongBinder(parcel, vector->at(index));
+}
+
+/**
+ * Reads an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index'
+ * from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readStdVectorParcelableElement<SpAIBinder>(const AParcel* parcel,
+ void* vectorData,
+ size_t index) {
+ std::vector<SpAIBinder>* vector = static_cast<std::vector<SpAIBinder>*>(vectorData);
+ return AParcel_readRequiredStrongBinder(parcel, &vector->at(index));
+}
+
+/**
+ * Writes an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index'
+ * to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<SpAIBinder>(
+ AParcel* parcel, const void* vectorData, size_t index) {
+ const std::optional<std::vector<SpAIBinder>>* vector =
+ static_cast<const std::optional<std::vector<SpAIBinder>>*>(vectorData);
+ return AParcel_writeNullableStrongBinder(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index'
+ * from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readNullableStdVectorParcelableElement<SpAIBinder>(
+ const AParcel* parcel, void* vectorData, size_t index) {
+ std::optional<std::vector<SpAIBinder>>* vector =
+ static_cast<std::optional<std::vector<SpAIBinder>>*>(vectorData);
+ return AParcel_readNullableStrongBinder(parcel, &(*vector)->at(index));
}
/**
@@ -598,6 +680,30 @@
AParcel_readStdVectorParcelableElement<P>);
}
+/**
+ * Convenience API for writing a std::optional<std::vector<P>>
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<P>>& vec) {
+ if (!vec) return AParcel_writeInt32(parcel, -1);
+ const void* vectorData = static_cast<const void*>(&vec);
+ return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec->size()),
+ AParcel_writeNullableStdVectorParcelableElement<P>);
+}
+
+/**
+ * Convenience API for reading a std::optional<std::vector<P>>
+ */
+template <typename P>
+static inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<P>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readParcelableArray(parcel, vectorData,
+ AParcel_nullableStdVectorExternalAllocator<P>,
+ AParcel_readNullableStdVectorParcelableElement<P>);
+}
+
// @START
/**
* Writes a vector of int32_t to the next location in a non-null parcel.
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..64170af 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -145,6 +145,7 @@
global:
AIBinder_Class_disableInterfaceTokenHeader;
AIBinder_DeathRecipient_setOnUnlinked;
+ AIBinder_setMinSchedulerPolicy; # llndk
AParcel_marshal;
AParcel_unmarshal;
};
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index d9d7caf..ecb044e 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -17,6 +17,7 @@
rustlibs: [
"liblibc",
"libbinder_ndk_sys",
+ "libdowncast_rs",
],
host_supported: true,
target: {
@@ -133,6 +134,7 @@
rustlibs: [
"liblibc",
"libbinder_ndk_sys",
+ "libdowncast_rs",
],
}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 41ceee5..cc5dd06 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,12 +17,13 @@
//! 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;
use std::borrow::Borrow;
use std::cmp::Ordering;
+use std::convert::TryFrom;
use std::ffi::{c_void, CStr, CString};
use std::fmt;
use std::fs::File;
@@ -70,6 +71,7 @@
/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
/// makes no stability guarantees ([`Local`]). [`Local`] is
/// currently the default stability.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Stability {
/// Default stability, visible to other modules in the same compilation
/// context (e.g. modules on system.img)
@@ -85,6 +87,28 @@
}
}
+impl From<Stability> for i32 {
+ fn from(stability: Stability) -> i32 {
+ use Stability::*;
+ match stability {
+ Local => 0,
+ Vintf => 1,
+ }
+ }
+}
+
+impl TryFrom<i32> for Stability {
+ type Error = StatusCode;
+ fn try_from(stability: i32) -> Result<Stability> {
+ use Stability::*;
+ match stability {
+ 0 => Ok(Local),
+ 1 => Ok(Vintf),
+ _ => Err(StatusCode::BAD_VALUE)
+ }
+ }
+}
+
/// A local service that can be remotable via Binder.
///
/// An object that implement this interface made be made into a Binder service
@@ -153,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
@@ -189,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)
}
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 7e8e3a5..81b620e 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -113,7 +113,7 @@
};
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};
@@ -127,7 +127,7 @@
/// The public API usable outside AIDL-generated interface crates.
pub mod public_api {
- pub use super::parcel::ParcelFileDescriptor;
+ pub use super::parcel::{ParcelFileDescriptor, ParcelableHolder};
pub use super::{
add_service, force_lazy_services_persist, get_interface, register_lazy_service,
wait_for_interface,
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index dad89ec..9dba950 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -23,17 +23,21 @@
use std::cell::RefCell;
use std::convert::TryInto;
+use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ptr;
use std::fmt;
mod file_descriptor;
mod parcelable;
+mod parcelable_holder;
pub use self::file_descriptor::ParcelFileDescriptor;
pub use self::parcelable::{
Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
+ Parcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
};
+pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};
/// Container for a message (data and object references) that can be sent
/// through Binder.
@@ -49,6 +53,106 @@
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 }
+ }
+
+ /// 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
@@ -68,6 +172,21 @@
}
impl Parcel {
+ /// Create a new empty `Parcel`.
+ ///
+ /// Creates a new owned empty parcel that can be written to
+ /// using the serialization methods and appended to and
+ /// from using `append_from` and `append_from_all`.
+ pub fn new() -> Parcel {
+ let parcel = unsafe {
+ // Safety: If `AParcel_create` succeeds, it always returns
+ // a valid pointer. If it fails, the process will crash.
+ sys::AParcel_create()
+ };
+ assert!(!parcel.is_null());
+ Self::Owned(parcel)
+ }
+
/// Create a borrowed reference to a parcel object from a raw pointer.
///
/// # Safety
@@ -77,32 +196,21 @@
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))
+impl Default for Parcel {
+ fn default() -> Self {
+ Self::new()
}
+}
- /// 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 Clone for Parcel {
+ fn clone(&self) -> Self {
+ let mut new_parcel = Self::new();
+ new_parcel
+ .append_all_from(self)
+ .expect("Failed to append from Parcel");
+ new_parcel
}
}
@@ -213,6 +321,30 @@
pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
}
+
+ /// Append a subset of another `Parcel`.
+ ///
+ /// This appends `size` bytes of data from `other` starting at offset
+ /// `start` to the current `Parcel`, or returns an error if not possible.
+ pub fn append_from(&mut self, other: &Self, start: i32, size: i32) -> Result<()> {
+ let status = unsafe {
+ // Safety: `Parcel::appendFrom` from C++ checks that `start`
+ // and `size` are in bounds, and returns an error otherwise.
+ // Both `self` and `other` always contain valid pointers.
+ sys::AParcel_appendFrom(
+ other.as_native(),
+ self.as_native_mut(),
+ start,
+ size,
+ )
+ };
+ status_result(status)
+ }
+
+ /// Append the contents of another `Parcel`.
+ pub fn append_all_from(&mut self, other: &Self) -> Result<()> {
+ self.append_from(other, 0, other.get_data_size())
+ }
}
/// A segment of a writable parcel, used for [`Parcel::sized_write`].
@@ -420,6 +552,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")
@@ -427,43 +571,16 @@
}
}
-#[cfg(test)]
-impl Parcel {
- /// Create a new parcel tied to a bogus binder. TESTING ONLY!
- ///
- /// This can only be used for testing! All real parcel operations must be
- /// done in the callback to [`IBinder::transact`] or in
- /// [`Remotable::on_transact`] using the parcels provided to these methods.
- pub(crate) fn new_for_test(binder: &mut SpIBinder) -> Result<Self> {
- let mut input = ptr::null_mut();
- let status = unsafe {
- // Safety: `SpIBinder` guarantees that `binder` always contains a
- // valid pointer to an `AIBinder`. We pass a valid, mutable out
- // pointer to receive a newly constructed parcel. When successful
- // this function assigns a new pointer to an `AParcel` to `input`
- // and transfers ownership of this pointer to the caller. Thus,
- // after this call, `input` will either be null or point to a valid,
- // owned `AParcel`.
- sys::AIBinder_prepareTransaction(binder.as_native_mut(), &mut input)
- };
- status_result(status)?;
- unsafe {
- // Safety: `input` is either null or a valid, owned pointer to an
- // `AParcel`, so is valid to safe to
- // `Parcel::owned`. `Parcel::owned` takes ownership of the parcel
- // pointer.
- Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)
- }
+impl fmt::Debug for OwnedParcel {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedParcel")
+ .finish()
}
}
#[test]
fn test_read_write() {
- use crate::binder::Interface;
- use crate::native::Binder;
-
- let mut service = Binder::new(()).as_binder();
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
assert_eq!(parcel.read::<bool>(), Err(StatusCode::NOT_ENOUGH_DATA));
@@ -493,11 +610,7 @@
#[test]
#[allow(clippy::float_cmp)]
fn test_read_data() {
- use crate::binder::Interface;
- use crate::native::Binder;
-
- let mut service = Binder::new(()).as_binder();
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let str_start = parcel.get_data_position();
parcel.write(&b"Hello, Binder!\0"[..]).unwrap();
@@ -572,11 +685,7 @@
#[test]
fn test_utf8_utf16_conversions() {
- use crate::binder::Interface;
- use crate::native::Binder;
-
- let mut service = Binder::new(()).as_binder();
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
assert!(parcel.write("Hello, Binder!").is_ok());
@@ -636,11 +745,7 @@
#[test]
fn test_sized_write() {
- use crate::binder::Interface;
- use crate::native::Binder;
-
- let mut service = Binder::new(()).as_binder();
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
let arr = [1i32, 2i32, 3i32];
@@ -668,3 +773,43 @@
&arr,
);
}
+
+#[test]
+fn test_append_from() {
+ let mut parcel1 = Parcel::new();
+ parcel1.write(&42i32).expect("Could not perform write");
+
+ let mut parcel2 = Parcel::new();
+ assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
+ assert_eq!(4, parcel2.get_data_size());
+ assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
+ assert_eq!(8, parcel2.get_data_size());
+ unsafe {
+ parcel2.set_data_position(0).unwrap();
+ }
+ assert_eq!(Ok(42), parcel2.read::<i32>());
+ assert_eq!(Ok(42), parcel2.read::<i32>());
+
+ let mut parcel2 = Parcel::new();
+ assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
+ assert_eq!(Ok(()), parcel2.append_from(&parcel1, 2, 2));
+ assert_eq!(4, parcel2.get_data_size());
+ unsafe {
+ parcel2.set_data_position(0).unwrap();
+ }
+ assert_eq!(Ok(42), parcel2.read::<i32>());
+
+ let mut parcel2 = Parcel::new();
+ assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
+ assert_eq!(2, parcel2.get_data_size());
+ unsafe {
+ parcel2.set_data_position(0).unwrap();
+ }
+ assert_eq!(Err(StatusCode::NOT_ENOUGH_DATA), parcel2.read::<i32>());
+
+ let mut parcel2 = Parcel::new();
+ assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 4, 2));
+ assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 2, 4));
+ assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, -1, 4));
+ assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 2, -1));
+}
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 56c6165..ec00e1d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -14,19 +14,42 @@
* limitations under the License.
*/
-use crate::binder::{AsNative, FromIBinder, Strong};
+use crate::binder::{AsNative, FromIBinder, Stability, Strong};
use crate::error::{status_result, status_t, Result, Status, StatusCode};
use crate::parcel::Parcel;
use crate::proxy::SpIBinder;
use crate::sys;
-use std::convert::TryInto;
+use std::convert::{TryFrom, TryInto};
use std::ffi::c_void;
use std::os::raw::{c_char, c_ulong};
use std::mem::{self, MaybeUninit};
use std::ptr;
use std::slice;
+/// Super-trait for Binder parcelables.
+///
+/// This trait is equivalent `android::Parcelable` in C++,
+/// and defines a common interface that all parcelables need
+/// to implement.
+pub trait Parcelable {
+ /// Internal serialization function for parcelables.
+ ///
+ /// This method is mainly for internal use.
+ /// `Serialize::serialize` and its variants are generally
+ /// preferred over this function, since the former also
+ /// prepend a header.
+ fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()>;
+
+ /// Internal deserialization function for parcelables.
+ ///
+ /// This method is mainly for internal use.
+ /// `Deserialize::deserialize` and its variants are generally
+ /// preferred over this function, since the former also
+ /// parse the additional header.
+ fn read_from_parcel(&mut self, parcel: &Parcel) -> Result<()>;
+}
+
/// A struct whose instances can be written to a [`Parcel`].
// Might be able to hook this up as a serde backend in the future?
pub trait Serialize {
@@ -162,6 +185,18 @@
StatusCode::OK as status_t
}
+/// Flag that specifies that the following parcelable is present.
+///
+/// This is the Rust equivalent of `Parcel::kNonNullParcelableFlag`
+/// from `include/binder/Parcel.h` in C++.
+pub const NON_NULL_PARCELABLE_FLAG: i32 = 1;
+
+/// Flag that specifies that the following parcelable is absent.
+///
+/// This is the Rust equivalent of `Parcel::kNullParcelableFlag`
+/// from `include/binder/Parcel.h` in C++.
+pub const NULL_PARCELABLE_FLAG: i32 = 0;
+
/// Helper trait for types that can be nullable when serialized.
// We really need this trait instead of implementing `Serialize for Option<T>`
// because of the Rust orphan rule which prevents us from doing
@@ -173,10 +208,10 @@
/// Serialize an Option of this type into the given [`Parcel`].
fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
if let Some(inner) = this {
- parcel.write(&1i32)?;
+ parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
parcel.write(inner)
} else {
- parcel.write(&0i32)
+ parcel.write(&NULL_PARCELABLE_FLAG)
}
}
}
@@ -186,7 +221,7 @@
/// Deserialize an Option of this type from the given [`Parcel`].
fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
let null: i32 = parcel.read()?;
- if null == 0 {
+ if null == NULL_PARCELABLE_FLAG {
Ok(None)
} else {
parcel.read().map(Some)
@@ -348,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;
@@ -502,8 +540,6 @@
}
}
-impl SerializeArray for Option<&str> {}
-
impl Serialize for str {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
Some(self).serialize(parcel)
@@ -526,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;
@@ -608,6 +642,18 @@
}
}
+impl Serialize for Stability {
+ fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ i32::from(*self).serialize(parcel)
+ }
+}
+
+impl Deserialize for Stability {
+ fn deserialize(parcel: &Parcel) -> Result<Self> {
+ i32::deserialize(parcel).and_then(Stability::try_from)
+ }
+}
+
impl Serialize for Status {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
unsafe {
@@ -699,19 +745,53 @@
}
}
+/// Implement `Serialize` trait and friends for a parcelable
+///
+/// This is an internal macro used by the AIDL compiler to implement
+/// `Serialize`, `SerializeArray` and `SerializeOption` for
+/// structured parcelables. The target type must implement the
+/// `Parcelable` trait.
+/// ```
+#[macro_export]
+macro_rules! impl_serialize_for_parcelable {
+ ($parcelable:ident) => {
+ impl $crate::parcel::Serialize for $parcelable {
+ fn serialize(
+ &self,
+ parcel: &mut $crate::parcel::Parcel,
+ ) -> $crate::Result<()> {
+ <Self as $crate::parcel::SerializeOption>::serialize_option(
+ Some(self),
+ parcel,
+ )
+ }
+ }
+
+ impl $crate::parcel::SerializeArray for $parcelable {}
+
+ impl $crate::parcel::SerializeOption for $parcelable {
+ fn serialize_option(
+ this: Option<&Self>,
+ parcel: &mut $crate::parcel::Parcel,
+ ) -> $crate::Result<()> {
+ if let Some(this) = this {
+ use $crate::parcel::Parcelable;
+ parcel.write(&$crate::parcel::NON_NULL_PARCELABLE_FLAG)?;
+ this.write_to_parcel(parcel)
+ } else {
+ parcel.write(&$crate::parcel::NULL_PARCELABLE_FLAG)
+ }
+ }
+ }
+ }
+}
+
/// Implement `Deserialize` trait and friends for a parcelable
///
/// This is an internal macro used by the AIDL compiler to implement
/// `Deserialize`, `DeserializeArray` and `DeserializeOption` for
-/// structured parcelables. The target type must implement a
-/// `deserialize_parcelable` method with the following signature:
-/// ```no_run
-/// fn deserialize_parcelable(
-/// &mut self,
-/// parcel: &binder::parcel::Parcelable,
-/// ) -> binder::Result<()> {
-/// // ...
-/// }
+/// structured parcelables. The target type must implement the
+/// `Parcelable` trait.
/// ```
#[macro_export]
macro_rules! impl_deserialize_for_parcelable {
@@ -729,10 +809,11 @@
parcel: &$crate::parcel::Parcel,
) -> $crate::Result<()> {
let status: i32 = parcel.read()?;
- if status == 0 {
+ if status == $crate::parcel::NULL_PARCELABLE_FLAG {
Err($crate::StatusCode::UNEXPECTED_NULL)
} else {
- self.deserialize_parcelable(parcel)
+ use $crate::parcel::Parcelable;
+ self.read_from_parcel(parcel)
}
}
}
@@ -752,12 +833,13 @@
parcel: &$crate::parcel::Parcel,
) -> $crate::Result<()> {
let status: i32 = parcel.read()?;
- if status == 0 {
+ if status == $crate::parcel::NULL_PARCELABLE_FLAG {
*this = None;
Ok(())
} else {
+ use $crate::parcel::Parcelable;
this.get_or_insert_with(Self::default)
- .deserialize_parcelable(parcel)
+ .read_from_parcel(parcel)
}
}
}
@@ -790,10 +872,6 @@
#[test]
fn test_custom_parcelable() {
- use crate::binder::Interface;
- use crate::native::Binder;
- let mut service = Binder::new(()).as_binder();
-
struct Custom(u32, bool, String, Vec<String>);
impl Serialize for Custom {
@@ -826,7 +904,7 @@
let custom = Custom(123_456_789, true, string8, strs);
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
assert!(custom.serialize(&mut parcel).is_ok());
@@ -846,13 +924,9 @@
#[test]
#[allow(clippy::excessive_precision)]
fn test_slice_parcelables() {
- use crate::binder::Interface;
- use crate::native::Binder;
- let mut service = Binder::new(()).as_binder();
-
let bools = [true, false, false, true];
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
assert!(bools.serialize(&mut parcel).is_ok());
@@ -876,7 +950,7 @@
let u8s = [101u8, 255, 42, 117];
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
assert!(parcel.write(&u8s[..]).is_ok());
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
new file mode 100644
index 0000000..bccfd2d
--- /dev/null
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -0,0 +1,261 @@
+/*
+ * 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 crate::binder::Stability;
+use crate::error::{Result, StatusCode};
+use crate::parcel::{OwnedParcel, Parcel, Parcelable};
+use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};
+
+use downcast_rs::{impl_downcast, DowncastSync};
+use std::any::Any;
+use std::sync::{Arc, Mutex};
+
+/// Metadata that `ParcelableHolder` needs for all parcelables.
+///
+/// The compiler auto-generates implementations of this trait
+/// for AIDL parcelables.
+pub trait ParcelableMetadata {
+ /// The Binder parcelable descriptor string.
+ ///
+ /// This string is a unique identifier for a Binder parcelable.
+ fn get_descriptor() -> &'static str;
+
+ /// The Binder parcelable stability.
+ fn get_stability(&self) -> Stability {
+ Stability::Local
+ }
+}
+
+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: Arc<dyn AnyParcelable>,
+ name: String,
+ },
+ Parcel(OwnedParcel),
+}
+
+impl Default for ParcelableHolderData {
+ fn default() -> Self {
+ ParcelableHolderData::Empty
+ }
+}
+
+/// A container that can hold any arbitrary `Parcelable`.
+///
+/// This type is currently used for AIDL parcelable fields.
+///
+/// `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)]
+pub struct ParcelableHolder {
+ // 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 `Mutex` here for a performance
+ // improvement, but then callers would require a mutable
+ // `ParcelableHolder` even for that getter method.
+ data: Mutex<ParcelableHolderData>,
+ stability: Stability,
+}
+
+impl ParcelableHolder {
+ /// Construct a new `ParcelableHolder` with the given stability.
+ pub fn new(stability: Stability) -> Self {
+ Self {
+ data: Mutex::new(ParcelableHolderData::Empty),
+ stability,
+ }
+ }
+
+ /// Reset the contents of this `ParcelableHolder`.
+ ///
+ /// Note that this method does not reset the stability,
+ /// only the contents.
+ pub fn reset(&mut self) {
+ *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: Arc<T>) -> Result<()>
+ where
+ T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
+ {
+ if self.stability > p.get_stability() {
+ return Err(StatusCode::BAD_VALUE);
+ }
+
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
+ parcelable: p,
+ name: T::get_descriptor().into(),
+ };
+
+ Ok(())
+ }
+
+ /// Retrieve the parcelable stored in this `ParcelableHolder`.
+ ///
+ /// This method attempts to retrieve the parcelable inside
+ /// the current object as a parcelable of type `T`.
+ /// The object is validated against `T` by checking that
+ /// its parcelable descriptor matches the one returned
+ /// by `T::get_descriptor()`.
+ ///
+ /// Returns one of the following:
+ /// * `Err(_)` in case of error
+ /// * `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<Arc<T>>>
+ where
+ T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
+ {
+ let parcelable_desc = T::get_descriptor();
+ let mut data = self.data.lock().unwrap();
+ match *data {
+ ParcelableHolderData::Empty => Ok(None),
+ ParcelableHolderData::Parcelable {
+ ref parcelable,
+ ref name,
+ } => {
+ if name != parcelable_desc {
+ return Err(StatusCode::BAD_VALUE);
+ }
+
+ match Arc::clone(parcelable).downcast_arc::<T>() {
+ Err(_) => Err(StatusCode::BAD_VALUE),
+ Ok(x) => Ok(Some(x)),
+ }
+ }
+ ParcelableHolderData::Parcel(ref mut parcel) => {
+ let parcel = parcel.borrowed();
+ unsafe {
+ // Safety: 0 should always be a valid position.
+ parcel.set_data_position(0)?;
+ }
+
+ let name: String = parcel.read()?;
+ if name != parcelable_desc {
+ return Ok(None);
+ }
+
+ let mut parcelable = T::default();
+ parcelable.read_from_parcel(&parcel)?;
+
+ let parcelable = Arc::new(parcelable);
+ let result = Arc::clone(&parcelable);
+ *data = ParcelableHolderData::Parcelable { parcelable, name };
+
+ Ok(Some(result))
+ }
+ }
+ }
+
+ /// Return the stability value of this object.
+ pub fn get_stability(&self) -> Stability {
+ self.stability
+ }
+}
+
+impl_serialize_for_parcelable!(ParcelableHolder);
+impl_deserialize_for_parcelable!(ParcelableHolder);
+
+impl Parcelable for ParcelableHolder {
+ fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
+ parcel.write(&self.stability)?;
+
+ let mut data = self.data.lock().unwrap();
+ match *data {
+ ParcelableHolderData::Empty => parcel.write(&0i32),
+ ParcelableHolderData::Parcelable {
+ ref parcelable,
+ ref name,
+ } => {
+ let length_start = parcel.get_data_position();
+ parcel.write(&0i32)?;
+
+ let data_start = parcel.get_data_position();
+ parcel.write(name)?;
+ parcelable.write_to_parcel(parcel)?;
+
+ let end = parcel.get_data_position();
+ unsafe {
+ // Safety: we got the position from `get_data_position`.
+ parcel.set_data_position(length_start)?;
+ }
+
+ assert!(end >= data_start);
+ parcel.write(&(end - data_start))?;
+ unsafe {
+ // Safety: we got the position from `get_data_position`.
+ parcel.set_data_position(end)?;
+ }
+
+ Ok(())
+ }
+ ParcelableHolderData::Parcel(ref mut p) => {
+ let p = p.borrowed();
+ parcel.write(&p.get_data_size())?;
+ parcel.append_all_from(&p)
+ }
+ }
+ }
+
+ fn read_from_parcel(&mut self, parcel: &Parcel) -> Result<()> {
+ self.stability = parcel.read()?;
+
+ let data_size: i32 = parcel.read()?;
+ if data_size < 0 {
+ // C++ returns BAD_VALUE here,
+ // while Java returns ILLEGAL_ARGUMENT
+ return Err(StatusCode::BAD_VALUE);
+ }
+ if data_size == 0 {
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
+ return Ok(());
+ }
+
+ // TODO: C++ ParcelableHolder accepts sizes up to SIZE_MAX here, but we
+ // only go up to i32::MAX because that's what our API uses everywhere
+ let data_start = parcel.get_data_position();
+ let data_end = data_start
+ .checked_add(data_size)
+ .ok_or(StatusCode::BAD_VALUE)?;
+
+ 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
+ // `parcel` and returns `BAD_VALUE` if that happens. We also
+ // explicitly check for negative and zero `data_size` above,
+ // so `data_end` is guaranteed to be greater than `data_start`.
+ parcel.set_data_position(data_end)?;
+ }
+
+ Ok(())
+ }
+}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 68fa34b..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,7 +427,6 @@
}
impl SerializeArray for SpIBinder {}
-impl SerializeArray for Option<&SpIBinder> {}
impl Deserialize for SpIBinder {
fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
@@ -447,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/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/Android.bp b/libs/binder/tests/Android.bp
index 680f0ed..86da588 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -87,6 +87,7 @@
srcs: ["binderParcelUnitTest.cpp", "binderBinderUnitTest.cpp"],
shared_libs: [
"libbinder",
+ "libcutils",
"libutils",
],
test_suites: ["general-tests"],
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/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
index eec3b44..464da60 100644
--- a/libs/binder/tests/binderHostDeviceTest.cpp
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -65,7 +65,9 @@
void initHostRpcServiceManagerOnce() {
static std::once_flag gSmOnce;
- std::call_once(gSmOnce, [] { setDefaultServiceManager(createRpcDelegateServiceManager()); });
+ std::call_once(gSmOnce, [] {
+ setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingThreads = 1}));
+ });
}
// Test for host service manager.
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index c69203b..c893899 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -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());
@@ -1189,7 +1194,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);
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index 841d47b..4950b23 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <cutils/ashmem.h>
#include <gtest/gtest.h>
using android::IPCThreadState;
@@ -146,3 +147,18 @@
TEST_READ_WRITE_INVERSE(int8_t, Byte, {-1, 0, 1});
TEST_READ_WRITE_INVERSE(String8, String8, {String8(), String8("a"), String8("asdf")});
TEST_READ_WRITE_INVERSE(String16, String16, {String16(), String16("a"), String16("asdf")});
+
+TEST(Parcel, GetOpenAshmemSize) {
+ constexpr size_t kSize = 1024;
+ constexpr size_t kCount = 3;
+
+ Parcel p;
+
+ for (size_t i = 0; i < kCount; i++) {
+ int fd = ashmem_create_region("test-getOpenAshmemSize", kSize);
+ ASSERT_GE(fd, 0);
+ ASSERT_EQ(OK, p.writeFileDescriptor(fd, true /* take ownership */));
+
+ ASSERT_EQ((kSize * (i + 1)), p.getOpenAshmemSize());
+ }
+}
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 a1058bc..7bbe3d7 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) {
@@ -481,6 +485,7 @@
size_t numThreads = 1;
size_t numSessions = 1;
size_t numIncomingConnections = 0;
+ size_t numOutgoingConnections = SIZE_MAX;
};
static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
@@ -537,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;
@@ -613,7 +617,8 @@
status_t status;
for (const auto& session : sessions) {
- session->setMaxThreads(options.numIncomingConnections);
+ session->setMaxIncomingThreads(options.numIncomingConnections);
+ session->setMaxOutgoingThreads(options.numOutgoingConnections);
switch (socketType) {
case SocketType::PRECONNECTED:
@@ -641,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;
@@ -655,6 +688,9 @@
return ret;
}
+
+ void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+ size_t sleepMs = 500);
};
TEST_P(BinderRpc, Ping) {
@@ -677,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;
@@ -685,13 +742,21 @@
}
TEST_P(BinderRpc, AppendSeparateFormats) {
- auto proc = createRpcTestSocketServerProcess({});
+ auto proc1 = createRpcTestSocketServerProcess({});
+ auto proc2 = createRpcTestSocketServerProcess({});
+
+ Parcel pRaw;
Parcel p1;
- p1.markForBinder(proc.rootBinder);
+ p1.markForBinder(proc1.rootBinder);
p1.writeInt32(3);
+ EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, p1.dataSize()));
+ EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
+
Parcel p2;
+ p2.markForBinder(proc2.rootBinder);
+ p2.writeInt32(7);
EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
@@ -996,28 +1061,39 @@
for (auto& t : ts) t.join();
}
-TEST_P(BinderRpc, ThreadPoolOverSaturated) {
- constexpr size_t kNumThreads = 10;
- constexpr size_t kNumCalls = kNumThreads + 3;
- constexpr size_t kSleepMs = 500;
-
- auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
-
+void BinderRpc::testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+ size_t sleepMs) {
size_t epochMsBefore = epochMillis();
std::vector<std::thread> ts;
- for (size_t i = 0; i < kNumCalls; i++) {
- ts.push_back(std::thread([&] { proc.rootIface->sleepMs(kSleepMs); }));
+ for (size_t i = 0; i < numCalls; i++) {
+ ts.push_back(std::thread([&] { iface->sleepMs(sleepMs); }));
}
for (auto& t : ts) t.join();
size_t epochMsAfter = epochMillis();
- EXPECT_GE(epochMsAfter, epochMsBefore + 2 * kSleepMs);
+ EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs);
// Potential flake, but make sure calls are handled in parallel.
- EXPECT_LE(epochMsAfter, epochMsBefore + 3 * kSleepMs);
+ EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs);
+}
+
+TEST_P(BinderRpc, ThreadPoolOverSaturated) {
+ constexpr size_t kNumThreads = 10;
+ constexpr size_t kNumCalls = kNumThreads + 3;
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
+}
+
+TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
+ constexpr size_t kNumThreads = 20;
+ constexpr size_t kNumOutgoingConnections = 10;
+ constexpr size_t kNumCalls = kNumOutgoingConnections + 3;
+ auto proc = createRpcTestSocketServerProcess(
+ {.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections});
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
}
TEST_P(BinderRpc, ThreadingStressTest) {
@@ -1283,11 +1359,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;
@@ -1376,7 +1461,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>();
@@ -1416,7 +1500,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();
@@ -1455,7 +1538,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";
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index f1fe164..e4f57b0 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -284,7 +284,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
@@ -301,6 +300,14 @@
FUZZ_LOG() << "ParcelableHolder status: " << status;
},
PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
+ [] (const ::android::Parcel& p, uint8_t /* data */) {
+ FUZZ_LOG() << "about to call hasFileDescriptorsInRange() with status";
+ size_t offset = p.readUint32();
+ size_t length = p.readUint32();
+ bool result;
+ status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
+ FUZZ_LOG() << " status: " << status << " result: " << result;
+ },
};
// clang-format on
#pragma clang diagnostic pop
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 6b783a4..c0a762d 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -95,6 +95,11 @@
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<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/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index e2f072a..61e6657 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -1134,6 +1134,18 @@
decodeByteVector);
}
+status_t encodeSmpte2094_10(const std::optional<std::vector<uint8_t>>& smpte2094_10,
+ hidl_vec<uint8_t>* outSmpte2094_10) {
+ return encodeOptionalMetadata(MetadataType_Smpte2094_10, smpte2094_10, outSmpte2094_10,
+ encodeByteVector);
+}
+
+status_t decodeSmpte2094_10(const hidl_vec<uint8_t>& smpte2094_10,
+ std::optional<std::vector<uint8_t>>* outSmpte2094_10) {
+ return decodeOptionalMetadata(MetadataType_Smpte2094_10, smpte2094_10, outSmpte2094_10,
+ decodeByteVector);
+}
+
status_t encodeUint32(const MetadataType& metadataType, uint32_t input,
hidl_vec<uint8_t>* output) {
return encodeMetadata(metadataType, input, output, encodeInteger);
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index 2f418ac..deaffad 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -134,6 +134,12 @@
aidl::android::hardware::graphics::common::
StandardMetadataType::SMPTE2094_40)};
+static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType
+ MetadataType_Smpte2094_10 = {GRALLOC4_STANDARD_METADATA_TYPE,
+ static_cast<int64_t>(
+ aidl::android::hardware::graphics::common::
+ StandardMetadataType::SMPTE2094_10)};
+
/*---------------------------------------------------------------------------------------------*/
/**
@@ -327,6 +333,11 @@
status_t decodeSmpte2094_40(const android::hardware::hidl_vec<uint8_t>& smpte2094_40,
std::optional<std::vector<uint8_t>>* outSmpte2094_40);
+status_t encodeSmpte2094_10(const std::optional<std::vector<uint8_t>>& smpte2094_10,
+ android::hardware::hidl_vec<uint8_t>* outSmpte2094_10);
+status_t decodeSmpte2094_10(const android::hardware::hidl_vec<uint8_t>& smpte2094_10,
+ std::optional<std::vector<uint8_t>>* outSmpte2094_10);
+
/**
* The functions below can be used to encode and decode vendor metadata types.
*/
diff --git a/libs/gralloc/types/tests/Gralloc4_test.cpp b/libs/gralloc/types/tests/Gralloc4_test.cpp
index 89cbf4a..94e344f 100644
--- a/libs/gralloc/types/tests/Gralloc4_test.cpp
+++ b/libs/gralloc/types/tests/Gralloc4_test.cpp
@@ -455,6 +455,32 @@
ASSERT_NO_FATAL_FAILURE(testHelperStableAidlTypeOptional(GetParam(), gralloc4::encodeSmpte2094_40, gralloc4::decodeSmpte2094_40));
}
+class Gralloc4TestSmpte2094_10
+ : public testing::TestWithParam<std::optional<std::vector<uint8_t>>> {};
+
+INSTANTIATE_TEST_CASE_P(
+ Gralloc4TestSmpte2094_10Params, Gralloc4TestSmpte2094_10,
+ ::testing::Values(
+ std::optional<std::vector<uint8_t>>({}),
+ std::optional<std::vector<uint8_t>>({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}),
+ std::optional<std::vector<uint8_t>>({std::numeric_limits<uint8_t>::min(),
+ std::numeric_limits<uint8_t>::min() + 1,
+ std::numeric_limits<uint8_t>::min() + 2,
+ std::numeric_limits<uint8_t>::min() + 3,
+ std::numeric_limits<uint8_t>::min() + 4}),
+ std::optional<std::vector<uint8_t>>({std::numeric_limits<uint8_t>::max(),
+ std::numeric_limits<uint8_t>::max() - 1,
+ std::numeric_limits<uint8_t>::max() - 2,
+ std::numeric_limits<uint8_t>::max() - 3,
+ std::numeric_limits<uint8_t>::max() - 4}),
+ std::nullopt));
+
+TEST_P(Gralloc4TestSmpte2094_10, Smpte2094_10) {
+ ASSERT_NO_FATAL_FAILURE(testHelperStableAidlTypeOptional(GetParam(),
+ gralloc4::encodeSmpte2094_10,
+ gralloc4::decodeSmpte2094_10));
+}
+
class Gralloc4TestBufferDescriptorInfo : public testing::TestWithParam<BufferDescriptorInfo> { };
INSTANTIATE_TEST_CASE_P(
@@ -491,6 +517,7 @@
ASSERT_NE(NO_ERROR, gralloc4::encodeSmpte2086({{}}, nullptr));
ASSERT_NE(NO_ERROR, gralloc4::encodeCta861_3({{}}, nullptr));
ASSERT_NE(NO_ERROR, gralloc4::encodeSmpte2094_40({{}}, nullptr));
+ ASSERT_NE(NO_ERROR, gralloc4::encodeSmpte2094_10({{}}, nullptr));
}
TEST_F(Gralloc4TestErrors, Gralloc4TestDecodeNull) {
@@ -516,6 +543,7 @@
ASSERT_NE(NO_ERROR, gralloc4::decodeSmpte2086(vec, nullptr));
ASSERT_NE(NO_ERROR, gralloc4::decodeCta861_3(vec, nullptr));
ASSERT_NE(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, nullptr));
+ ASSERT_NE(NO_ERROR, gralloc4::decodeSmpte2094_10(vec, nullptr));
}
TEST_F(Gralloc4TestErrors, Gralloc4TestDecodeBadVec) {
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 2b17616..1ae90f3 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -46,6 +46,8 @@
namespace android {
// Macros to include adapter info in log messages
+#define BQA_LOGD(x, ...) \
+ ALOGD("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
#define BQA_LOGV(x, ...) \
ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
// enable logs for a single layer
@@ -162,6 +164,7 @@
ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
+ mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -243,6 +246,67 @@
}
}
+static std::optional<SurfaceControlStats> findMatchingStat(
+ const std::vector<SurfaceControlStats>& stats, const sp<SurfaceControl>& sc) {
+ for (auto stat : stats) {
+ if (SurfaceControl::isSameSurface(sc, stat.surfaceControl)) {
+ return stat;
+ }
+ }
+ return std::nullopt;
+}
+
+static void transactionCommittedCallbackThunk(void* context, nsecs_t latchTime,
+ const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ if (context == nullptr) {
+ return;
+ }
+ sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context);
+ bq->transactionCommittedCallback(latchTime, presentFence, stats);
+}
+
+void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/,
+ const sp<Fence>& /*presentFence*/,
+ const std::vector<SurfaceControlStats>& stats) {
+ {
+ std::unique_lock _lock{mMutex};
+ ATRACE_CALL();
+ BQA_LOGV("transactionCommittedCallback");
+ if (!mSurfaceControlsWithPendingCallback.empty()) {
+ sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
+ std::optional<SurfaceControlStats> stat = findMatchingStat(stats, pendingSC);
+ if (stat) {
+ uint64_t currFrameNumber = stat->frameEventStats.frameNumber;
+
+ // We need to check if we were waiting for a transaction callback in order to
+ // process any pending buffers and unblock. It's possible to get transaction
+ // callbacks for previous requests so we need to ensure the frame from this
+ // transaction callback matches the last acquired buffer. Since acquireNextBuffer
+ // will stop processing buffers when mWaitForTransactionCallback is set, we know
+ // that mLastAcquiredFrameNumber is the frame we're waiting on.
+ // We also want to check if mNextTransaction is null because it's possible another
+ // sync request came in while waiting, but it hasn't started processing yet. In that
+ // case, we don't actually want to flush the frames in between since they will get
+ // processed and merged with the sync transaction and released earlier than if they
+ // were sent to SF
+ if (mWaitForTransactionCallback && mNextTransaction == nullptr &&
+ currFrameNumber >= mLastAcquiredFrameNumber) {
+ mWaitForTransactionCallback = false;
+ flushShadowQueue();
+ }
+ } else {
+ BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
+ }
+ } else {
+ BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
+ "empty.");
+ }
+
+ decStrong((void*)transactionCommittedCallbackThunk);
+ }
+}
+
static void transactionCallbackThunk(void* context, nsecs_t latchTime,
const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats) {
@@ -255,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();
@@ -266,12 +327,9 @@
if (!mSurfaceControlsWithPendingCallback.empty()) {
sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
mSurfaceControlsWithPendingCallback.pop();
- bool found = false;
- for (auto stat : stats) {
- if (!SurfaceControl::isSameSurface(pendingSC, stat.surfaceControl)) {
- continue;
- }
-
+ std::optional<SurfaceControlStats> statsOptional = findMatchingStat(stats, pendingSC);
+ if (statsOptional) {
+ SurfaceControlStats stat = *statsOptional;
mTransformHint = stat.transformHint;
mBufferItemConsumer->setTransformHint(mTransformHint);
BQA_LOGV("updated mTransformHint=%d", mTransformHint);
@@ -287,24 +345,7 @@
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;
- }
-
- found = true;
- break;
- }
-
- if (!found) {
+ } else {
BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
}
} else {
@@ -314,10 +355,6 @@
decStrong((void*)transactionCallbackThunk);
}
-
- if (transactionCompleteCallback) {
- transactionCompleteCallback(currFrameNumber);
- }
}
// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
@@ -325,31 +362,32 @@
// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
// Otherwise, this is a no-op.
static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const ReleaseCallbackId& id,
- const sp<Fence>& releaseFence, uint32_t transformHint,
- uint32_t currentMaxAcquiredBufferCount) {
+ const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount) {
sp<BLASTBufferQueue> blastBufferQueue = context.promote();
if (blastBufferQueue) {
- blastBufferQueue->releaseBufferCallback(id, releaseFence, transformHint,
- currentMaxAcquiredBufferCount);
+ blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
} else {
ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str());
}
}
-void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
- const sp<Fence>& releaseFence, uint32_t transformHint,
- uint32_t currentMaxAcquiredBufferCount) {
+void BLASTBufferQueue::flushShadowQueue() {
+ BQA_LOGV("flushShadowQueue");
+ int numFramesToFlush = mNumFrameAvailable;
+ while (numFramesToFlush > 0) {
+ acquireNextBufferLocked(std::nullopt);
+ numFramesToFlush--;
+ }
+}
+
+void BLASTBufferQueue::releaseBufferCallback(
+ const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount) {
ATRACE_CALL();
std::unique_lock _lock{mMutex};
BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
- if (mSurfaceControl != nullptr) {
- mTransformHint = transformHint;
- mSurfaceControl->setTransformHint(transformHint);
- mBufferItemConsumer->setTransformHint(mTransformHint);
- BQA_LOGV("updated mTransformHint=%d", mTransformHint);
- }
-
// Calculate how many buffers we need to hold before we release them back
// to the buffer queue. This will prevent higher latency when we are running
// on a lower refresh rate than the max supported. We only do that for EGL
@@ -359,8 +397,12 @@
return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
}();
+ if (currentMaxAcquiredBufferCount) {
+ mCurrentMaxAcquiredBufferCount = *currentMaxAcquiredBufferCount;
+ }
+
const auto numPendingBuffersToHold =
- isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
+ isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0;
mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence});
// Release all buffers that are beyond the ones that we need to hold
@@ -374,10 +416,14 @@
return;
}
mNumAcquired--;
- BQA_LOGV("released %s", id.to_string().c_str());
+ BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str());
mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
mSubmitted.erase(it);
- processNextBufferLocked(false /* useNextTransaction */);
+ // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
+ // onFrameAvailable handle processing them since it will merge with the nextTransaction.
+ if (!mWaitForTransactionCallback) {
+ acquireNextBufferLocked(std::nullopt);
+ }
}
ATRACE_INT("PendingRelease", mPendingRelease.size());
@@ -386,13 +432,15 @@
mCallbackCV.notify_all();
}
-void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
+void BLASTBufferQueue::acquireNextBufferLocked(
+ const std::optional<SurfaceComposerClient::Transaction*> transaction) {
ATRACE_CALL();
// If the next transaction is set, we want to guarantee the our acquire will not fail, so don't
// include the extra buffer when checking if we can acquire the next buffer.
- const bool includeExtraAcquire = !useNextTransaction;
- if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) {
- mCallbackCV.notify_all();
+ const bool includeExtraAcquire = !transaction;
+ const bool maxAcquired = maxBuffersAcquired(includeExtraAcquire);
+ if (mNumFrameAvailable == 0 || maxAcquired) {
+ BQA_LOGV("Can't process next buffer maxBuffersAcquired=%s", boolToString(maxAcquired));
return;
}
@@ -404,9 +452,8 @@
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
SurfaceComposerClient::Transaction* t = &localTransaction;
- if (mNextTransaction != nullptr && useNextTransaction) {
- t = mNextTransaction;
- mNextTransaction = nullptr;
+ if (transaction) {
+ t = *transaction;
applyTransaction = false;
}
@@ -436,7 +483,7 @@
mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
- processNextBufferLocked(useNextTransaction);
+ acquireNextBufferLocked(transaction);
return;
}
@@ -455,6 +502,7 @@
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
+ incStrong((void*)transactionCommittedCallbackThunk);
const bool sizeHasChanged = mRequestedSize != mSize;
mSize = mRequestedSize;
@@ -466,8 +514,7 @@
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
- std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
- std::placeholders::_4);
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId,
releaseBufferCallback);
@@ -475,6 +522,7 @@
t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
+ t->addTransactionCommittedCallback(transactionCommittedCallbackThunk, static_cast<void*>(this));
mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
if (updateDestinationFrame) {
@@ -512,7 +560,7 @@
t->setApplyToken(mApplyToken).apply();
}
- BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
+ BQA_LOGV("acquireNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
" applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
" graphicBufferId=%" PRIu64 "%s transform=%d",
mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction),
@@ -528,17 +576,50 @@
return item.mCrop;
}
+void BLASTBufferQueue::acquireAndReleaseBuffer() {
+ BufferItem bufferItem;
+ status_t status =
+ mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
+ if (status != OK) {
+ BQA_LOGE("Failed to acquire a buffer in acquireAndReleaseBuffer, err=%s",
+ statusToString(status).c_str());
+ return;
+ }
+ mNumFrameAvailable--;
+ mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence);
+}
+
void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
ATRACE_CALL();
std::unique_lock _lock{mMutex};
const bool nextTransactionSet = mNextTransaction != nullptr;
+ BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet));
if (nextTransactionSet) {
- while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) {
- BQA_LOGV("waiting in onFrameAvailable...");
+ if (mWaitForTransactionCallback) {
+ // We are waiting on a previous sync's transaction callback so allow another sync
+ // transaction to proceed.
+ //
+ // We need to first flush out the transactions that were in between the two syncs.
+ // We do this by merging them into mNextTransaction so any buffer merging will get
+ // a release callback invoked. The release callback will be async so we need to wait
+ // on max acquired to make sure we have the capacity to acquire another buffer.
+ if (maxBuffersAcquired(false /* includeExtraAcquire */)) {
+ BQA_LOGD("waiting to flush shadow queue...");
+ mCallbackCV.wait(_lock);
+ }
+ while (mNumFrameAvailable > 0) {
+ // flush out the shadow queue
+ acquireAndReleaseBuffer();
+ }
+ }
+
+ while (maxBuffersAcquired(false /* includeExtraAcquire */)) {
+ BQA_LOGD("waiting for free buffer.");
mCallbackCV.wait(_lock);
}
}
+
// add to shadow queue
mNumFrameAvailable++;
ATRACE_INT(mQueuedBufferTrace.c_str(),
@@ -546,7 +627,14 @@
BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber,
boolToString(nextTransactionSet));
- processNextBufferLocked(nextTransactionSet /* useNextTransaction */);
+
+ if (nextTransactionSet) {
+ acquireNextBufferLocked(std::move(mNextTransaction));
+ mNextTransaction = nullptr;
+ mWaitForTransactionCallback = true;
+ } else if (!mWaitForTransactionCallback) {
+ acquireNextBufferLocked(std::nullopt);
+ }
}
void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {
@@ -591,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/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 6f1a7ae..c986b82 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -130,6 +130,19 @@
return 1; // keep the callback
}
+void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event,
+ VsyncEventData* outVsyncEventData) const {
+ for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) {
+ DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline =
+ event.vsync.frameTimelines[i];
+ outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId,
+ .deadlineTimestamp =
+ receiverTimeline.deadlineTimestamp,
+ .expectedPresentTime =
+ receiverTimeline.expectedVSyncTimestamp};
+ }
+}
+
bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
PhysicalDisplayId* outDisplayId,
uint32_t* outCount,
@@ -154,6 +167,9 @@
outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
outVsyncEventData->frameInterval = ev.vsync.frameInterval;
outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp;
+ outVsyncEventData->preferredFrameTimelineIndex =
+ ev.vsync.preferredFrameTimelineIndex;
+ populateFrameTimelines(ev, outVsyncEventData);
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 98e8b54..aa7ebc9 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -254,11 +254,10 @@
}
void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
- uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override {
+ uint32_t currentMaxAcquiredBufferCount) override {
callRemoteAsync<decltype(
&ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER,
callbackId, releaseFence,
- transformHint,
currentMaxAcquiredBufferCount);
}
};
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index aca59b6..2713be0 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -214,12 +214,6 @@
mReleaseBufferCallbacks[callbackId] = listener;
}
-void TransactionCompletedListener::removeReleaseBufferCallback(
- const ReleaseCallbackId& callbackId) {
- std::scoped_lock<std::mutex> lock(mMutex);
- mReleaseBufferCallbacks.erase(callbackId);
-}
-
void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex);
@@ -343,7 +337,6 @@
surfaceStats.previousReleaseFence
? surfaceStats.previousReleaseFence
: Fence::NO_FENCE,
- surfaceStats.transformHint,
surfaceStats.currentMaxAcquiredBufferCount);
}
}
@@ -389,7 +382,7 @@
}
void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId,
- sp<Fence> releaseFence, uint32_t transformHint,
+ sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) {
ReleaseBufferCallback callback;
{
@@ -401,7 +394,11 @@
callbackId.to_string().c_str());
return;
}
- callback(callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount);
+ std::optional<uint32_t> optionalMaxAcquiredBufferCount =
+ currentMaxAcquiredBufferCount == UINT_MAX
+ ? std::nullopt
+ : std::make_optional<uint32_t>(currentMaxAcquiredBufferCount);
+ callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount);
}
ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked(
@@ -712,11 +709,34 @@
return NO_ERROR;
}
+void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_state_t& state) {
+ if (!(state.what & layer_state_t::eBufferChanged)) {
+ return;
+ }
+
+ auto listener = state.bufferData.releaseBufferListener;
+ sp<Fence> fence =
+ state.bufferData.acquireFence ? state.bufferData.acquireFence : Fence::NO_FENCE;
+ if (state.bufferData.releaseBufferEndpoint ==
+ IInterface::asBinder(TransactionCompletedListener::getIInstance())) {
+ // if the callback is in process, run on a different thread to avoid any lock contigency
+ // issues in the client.
+ SurfaceComposerClient::getDefault()
+ ->mReleaseCallbackThread.addReleaseCallback(state.bufferData.releaseCallbackId,
+ fence);
+ } else {
+ listener->onReleaseBuffer(state.bufferData.releaseCallbackId, fence, UINT_MAX);
+ }
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
for (auto const& [handle, composerState] : other.mComposerStates) {
if (mComposerStates.count(handle) == 0) {
mComposerStates[handle] = composerState;
} else {
+ if (composerState.state.what & layer_state_t::eBufferChanged) {
+ releaseBufferIfOverwriting(mComposerStates[handle].state);
+ }
mComposerStates[handle].state.merge(composerState.state);
}
}
@@ -1296,7 +1316,9 @@
mStatus = BAD_INDEX;
return *this;
}
- removeReleaseBufferCallback(s);
+
+ releaseBufferIfOverwriting(*s);
+
BufferData bufferData;
bufferData.buffer = buffer;
if (frameNumber) {
@@ -1321,15 +1343,6 @@
return *this;
}
-void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) {
- if (!(s->what & layer_state_t::eBufferChanged)) {
- return;
- }
-
- auto listener = TransactionCompletedListener::getInstance();
- listener->removeReleaseBufferCallback(s->bufferData.releaseCallbackId);
-}
-
void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData,
const ReleaseCallbackId& id,
ReleaseBufferCallback callback) {
@@ -2210,4 +2223,43 @@
return s->captureLayers(captureArgs, captureListener);
}
+// ---------------------------------------------------------------------------------
+
+void ReleaseCallbackThread::addReleaseCallback(const ReleaseCallbackId callbackId,
+ sp<Fence> releaseFence) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ if (!mStarted) {
+ mThread = std::thread(&ReleaseCallbackThread::threadMain, this);
+ mStarted = true;
+ }
+
+ mCallbackInfos.emplace(callbackId, std::move(releaseFence));
+ mReleaseCallbackPending.notify_one();
+}
+
+void ReleaseCallbackThread::threadMain() {
+ const auto listener = TransactionCompletedListener::getInstance();
+ std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> callbackInfos;
+ while (true) {
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ callbackInfos = std::move(mCallbackInfos);
+ mCallbackInfos = {};
+ }
+
+ while (!callbackInfos.empty()) {
+ auto [callbackId, releaseFence] = callbackInfos.front();
+ listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX);
+ callbackInfos.pop();
+ }
+
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mCallbackInfos.size() == 0) {
+ mReleaseCallbackPending.wait(lock);
+ }
+ }
+ }
+}
+
} // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 1f517f6..3881620 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -88,15 +88,15 @@
void onFrameDequeued(const uint64_t) override;
void onFrameCancelled(const uint64_t) override;
+ 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,
- uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
+ std::optional<uint32_t> currentMaxAcquiredBufferCount);
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);
@@ -120,7 +120,8 @@
void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer);
- void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
+ void acquireNextBufferLocked(
+ const std::optional<SurfaceComposerClient::Transaction*> transaction) REQUIRES(mMutex);
Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
// Return true if we need to reject the buffer based on the scaling mode and the buffer size.
bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
@@ -129,6 +130,9 @@
void mergePendingTransactions(SurfaceComposerClient::Transaction* t, uint64_t frameNumber)
REQUIRES(mMutex);
+ void flushShadowQueue() REQUIRES(mMutex);
+ void acquireAndReleaseBuffer() REQUIRES(mMutex);
+
std::string mName;
// Represents the queued buffer count from buffer queue,
// pre-BLAST. This is mNumFrameAvailable (buffers that queued to blast) +
@@ -218,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();
@@ -236,6 +237,9 @@
// Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a
// callback for them.
std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex);
+
+ uint32_t mCurrentMaxAcquiredBufferCount;
+ bool mWaitForTransactionCallback = false;
};
} // namespace android
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index f3bd139..92c89b8 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -17,6 +17,7 @@
#include <gui/DisplayEventReceiver.h>
#include <utils/Log.h>
#include <utils/Looper.h>
+#include <array>
namespace android {
using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
@@ -36,6 +37,26 @@
// The anticipated Vsync present time.
int64_t expectedPresentTime = 0;
+
+ struct FrameTimeline {
+ // The Vsync Id corresponsing to this vsync event. This will be used to
+ // populate ISurfaceComposer::setFrameTimelineVsync and
+ // SurfaceComposerClient::setFrameTimelineVsync
+ int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
+
+ // The deadline in CLOCK_MONOTONIC that the app needs to complete its
+ // frame by (both on the CPU and the GPU)
+ int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
+
+ // The anticipated Vsync present time.
+ int64_t expectedPresentTime = 0;
+ };
+
+ // Sorted possible frame timelines.
+ std::array<FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength> frameTimelines;
+
+ // Index into the frameTimelines that represents the platform's preferred frame timeline.
+ size_t preferredFrameTimelineIndex = std::numeric_limits<size_t>::max();
};
class DisplayEventDispatcher : public LooperCallback {
@@ -77,5 +98,8 @@
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
uint32_t* outCount, VsyncEventData* outVsyncEventData);
+
+ void populateFrameTimelines(const DisplayEventReceiver::Event& event,
+ VsyncEventData* outVsyncEventData) const;
};
} // namespace android
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 0dffbde..ca36843 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -49,6 +49,9 @@
// ----------------------------------------------------------------------------
class DisplayEventReceiver {
public:
+ // Max amount of frame timelines is arbitrarily set to be reasonable.
+ static constexpr int64_t kFrameTimelinesLength = 7;
+
enum {
DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
@@ -77,6 +80,12 @@
nsecs_t deadlineTimestamp __attribute__((aligned(8)));
nsecs_t frameInterval __attribute__((aligned(8)));
int64_t vsyncId;
+ size_t preferredFrameTimelineIndex __attribute__((aligned(8)));
+ struct FrameTimeline {
+ nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
+ nsecs_t deadlineTimestamp __attribute__((aligned(8)));
+ int64_t vsyncId;
+ } frameTimelines[kFrameTimelinesLength];
};
struct Hotplug {
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 937095c..0df5822 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -192,7 +192,6 @@
virtual void onTransactionCompleted(ListenerStats stats) = 0;
virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
- uint32_t transformHint,
uint32_t currentMaxAcquiredBufferCount) = 0;
};
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/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 82249a3..e62c76e 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <set>
+#include <thread>
#include <unordered_map>
#include <unordered_set>
@@ -84,7 +85,7 @@
const std::vector<SurfaceControlStats>& /*stats*/)>;
using ReleaseBufferCallback =
std::function<void(const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/,
- uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount)>;
+ std::optional<uint32_t> currentMaxAcquiredBufferCount)>;
using SurfaceStatsCallback =
std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
@@ -93,6 +94,22 @@
// ---------------------------------------------------------------------------
+class ReleaseCallbackThread {
+public:
+ void addReleaseCallback(const ReleaseCallbackId, sp<Fence>);
+ void threadMain();
+
+private:
+ std::thread mThread;
+ std::mutex mMutex;
+ bool mStarted GUARDED_BY(mMutex) = false;
+ std::condition_variable mReleaseCallbackPending;
+ std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> mCallbackInfos
+ GUARDED_BY(mMutex);
+};
+
+// ---------------------------------------------------------------------------
+
class SurfaceComposerClient : public RefBase
{
friend class Composer;
@@ -350,6 +367,7 @@
private:
static std::atomic<uint32_t> idCounter;
int64_t generateId();
+ void releaseBufferIfOverwriting(const layer_state_t& state);
protected:
std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
@@ -400,7 +418,6 @@
void cacheBuffers();
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
void setReleaseBufferCallback(BufferData*, const ReleaseCallbackId&, ReleaseBufferCallback);
- void removeReleaseBufferCallback(layer_state_t*);
public:
Transaction();
@@ -625,6 +642,9 @@
status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
+protected:
+ ReleaseCallbackThread mReleaseCallbackThread;
+
private:
virtual void onFirstRef();
@@ -725,11 +745,10 @@
void removeSurfaceStatsListener(void* context, void* cookie);
void setReleaseBufferCallback(const ReleaseCallbackId&, ReleaseBufferCallback);
- void removeReleaseBufferCallback(const ReleaseCallbackId&);
// BnTransactionCompletedListener overrides
void onTransactionCompleted(ListenerStats stats) override;
- void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint,
+ void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) override;
// For Testing Only
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
similarity index 96%
rename from services/surfaceflinger/tests/utils/CallbackUtils.h
rename to libs/gui/include/gui/test/CallbackUtils.h
index f4a3425..6403208 100644
--- a/services/surfaceflinger/tests/utils/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -134,10 +134,8 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
- const auto&
- [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
- transformHint,
- frameEvents] = surfaceControlStats;
+ const auto& [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
+ transformHint, frameEvents] = surfaceControlStats;
ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";
@@ -199,7 +197,7 @@
std::this_thread::sleep_for(500ms);
std::lock_guard lock(mMutex);
- EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+ EXPECT_EQ(mCallbackDataQueue.size(), 0U) << "extra callbacks received";
mCallbackDataQueue = {};
}
@@ -209,5 +207,5 @@
std::condition_variable mConditionVariable;
std::queue<CallbackData> mCallbackDataQueue;
};
-}
+} // namespace
} // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index b474086..b2d5048 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -27,6 +27,7 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SyncScreenCaptureListener.h>
+#include <gui/test/CallbackUtils.h>
#include <private/gui/ComposerService.h>
#include <ui/DisplayMode.h>
#include <ui/GraphicBuffer.h>
@@ -42,11 +43,67 @@
using Transaction = SurfaceComposerClient::Transaction;
using android::hardware::graphics::common::V1_2::BufferUsage;
+class CountProducerListener : public BnProducerListener {
+public:
+ void onBufferReleased() override {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mNumReleased++;
+ mReleaseCallback.notify_one();
+ }
+
+ void waitOnNumberReleased(int32_t expectedNumReleased) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mNumReleased < expectedNumReleased) {
+ ASSERT_NE(mReleaseCallback.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive release";
+ }
+ }
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mReleaseCallback;
+ 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) {
@@ -83,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 {
@@ -152,18 +193,19 @@
mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB;
}
- void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer) {
+ void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer,
+ int32_t maxBufferCount = 2) {
producer = adapter.getIGraphicBufferProducer();
- setUpProducer(producer);
+ setUpProducer(producer, maxBufferCount);
}
- void setUpProducer(sp<IGraphicBufferProducer>& igbProducer) {
+ void setUpProducer(sp<IGraphicBufferProducer>& igbProducer, int32_t maxBufferCount) {
ASSERT_NE(nullptr, igbProducer.get());
- ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
+ ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(maxBufferCount));
IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ mProducerListener = new CountProducerListener();
ASSERT_EQ(NO_ERROR,
- igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
- &qbOutput));
+ igbProducer->connect(mProducerListener, NATIVE_WINDOW_API_CPU, false, &qbOutput));
ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
}
@@ -287,6 +329,7 @@
DisplayCaptureArgs mCaptureArgs;
ScreenCaptureResults mCaptureResults;
+ sp<CountProducerListener> mProducerListener;
};
TEST_F(BLASTBufferQueueTest, CreateBLASTBufferQueue) {
@@ -749,6 +792,240 @@
{0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2}));
}
+TEST_F(BLASTBufferQueueTest, SyncThenNoSync) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction next;
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ // queue non sync buffer, so this one should get blocked
+ // Add a present delay to allow the first screenshot to get taken.
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ queueBuffer(igbProducer, r, g, b, presentTimeDelay);
+
+ CallbackHelper transactionCallback;
+ next.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+
+ mProducerListener->waitOnNumberReleased(1);
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
+TEST_F(BLASTBufferQueueTest, MultipleSyncTransactions) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction mainTransaction;
+
+ Transaction next;
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ mainTransaction.merge(std::move(next));
+
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, r, g, b, 0);
+
+ mainTransaction.merge(std::move(next));
+ // Expect 1 buffer to be released even before sending to SurfaceFlinger
+ mProducerListener->waitOnNumberReleased(1);
+
+ CallbackHelper transactionCallback;
+ mainTransaction
+ .addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
+TEST_F(BLASTBufferQueueTest, MultipleSyncTransactionWithNonSync) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction mainTransaction;
+
+ Transaction next;
+ // queue a sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ mainTransaction.merge(std::move(next));
+
+ // queue another buffer without setting next transaction
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+
+ // queue another sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, r, g, b, 0);
+ // Expect 1 buffer to be released because the non sync transaction should merge
+ // with the sync
+ mProducerListener->waitOnNumberReleased(1);
+
+ mainTransaction.merge(std::move(next));
+ // Expect 2 buffers to be released due to merging the two syncs.
+ mProducerListener->waitOnNumberReleased(2);
+
+ CallbackHelper transactionCallback;
+ mainTransaction
+ .addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
+TEST_F(BLASTBufferQueueTest, MultipleSyncRunOutOfBuffers) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer, 3);
+
+ Transaction mainTransaction;
+
+ Transaction next;
+ // queue a sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ mainTransaction.merge(std::move(next));
+
+ // queue a few buffers without setting next transaction
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+
+ // queue another sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, r, g, b, 0);
+ // Expect 3 buffers to be released because the non sync transactions should merge
+ // with the sync
+ mProducerListener->waitOnNumberReleased(3);
+
+ mainTransaction.merge(std::move(next));
+ // Expect 4 buffers to be released due to merging the two syncs.
+ mProducerListener->waitOnNumberReleased(4);
+
+ CallbackHelper transactionCallback;
+ mainTransaction
+ .addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
+// Tests BBQ with a sync transaction when the buffers acquired reaches max and the only way to
+// continue processing is for a release callback from SurfaceFlinger.
+// This is done by sending a buffer to SF so it can release the previous one and allow BBQ to
+// continue acquiring buffers.
+TEST_F(BLASTBufferQueueTest, RunOutOfBuffersWaitingOnSF) {
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer, 4);
+
+ Transaction mainTransaction;
+
+ // Send a buffer to SF
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ Transaction next;
+ // queue a sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ mainTransaction.merge(std::move(next));
+
+ // queue a few buffers without setting next transaction
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+
+ // apply the first synced buffer to ensure we have to wait on SF
+ mainTransaction.apply();
+
+ // queue another sync transaction
+ adapter.setNextTransaction(&next);
+ queueBuffer(igbProducer, r, g, b, 0);
+ // Expect 2 buffers to be released because the non sync transactions should merge
+ // with the sync
+ mProducerListener->waitOnNumberReleased(3);
+
+ mainTransaction.merge(std::move(next));
+
+ CallbackHelper transactionCallback;
+ mainTransaction
+ .addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
class TestProducerListener : public BnProducerListener {
public:
sp<IGraphicBufferProducer> mIgbp;
@@ -1106,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);
@@ -1175,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);
@@ -1241,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/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 16208a7..d9beb23 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -569,7 +569,7 @@
bufferSurface->expectTap(1, 1);
}
-TEST_F(InputSurfacesTest, input_ignores_buffer_layer_alpha) {
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_alpha) {
std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
std::unique_ptr<BlastInputSurface> bufferSurface =
BlastInputSurface::makeBlastInputSurface(mComposerClient, 100, 100);
@@ -584,7 +584,7 @@
bufferSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
injectTap(11, 11);
- bufferSurface->expectTap(1, 1);
+ bgSurface->expectTap(1, 1);
}
TEST_F(InputSurfacesTest, input_ignores_color_layer_alpha) {
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/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/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 79d9b93..fc9680b 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -100,17 +100,10 @@
* Implementation of AChoreographerFrameCallbackData.
*/
struct ChoreographerFrameCallbackDataImpl {
- struct FrameTimeline {
- int64_t vsyncId{0};
- int64_t expectedPresentTimeNanos{0};
- int64_t deadlineNanos{0};
- };
-
int64_t frameTimeNanos{0};
- size_t frameTimelinesLength;
-
- std::vector<FrameTimeline> frameTimelines;
+ std::array<VsyncEventData::FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength>
+ frameTimelines;
size_t preferredFrameTimelineIndex;
@@ -456,14 +449,9 @@
}
ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const {
- std::vector<ChoreographerFrameCallbackDataImpl::FrameTimeline> frameTimelines;
- frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id,
- .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime,
- .deadlineNanos = mLastVsyncEventData.deadlineTimestamp});
return {.frameTimeNanos = timestamp,
- .frameTimelinesLength = 1,
- .preferredFrameTimelineIndex = 0,
- .frameTimelines = frameTimelines,
+ .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex,
+ .frameTimelines = mLastVsyncEventData.frameTimelines,
.choreographer = this};
}
@@ -646,7 +634,7 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- return frameCallbackData->frameTimelinesLength;
+ return frameCallbackData->frameTimelines.size();
}
size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
const AChoreographerFrameCallbackData* data) {
@@ -662,8 +650,8 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
- return frameCallbackData->frameTimelines[index].vsyncId;
+ LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
+ return frameCallbackData->frameTimelines[index].id;
}
int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
const AChoreographerFrameCallbackData* data, size_t index) {
@@ -671,8 +659,8 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
- return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos;
+ LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
+ return frameCallbackData->frameTimelines[index].expectedPresentTime;
}
int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
const AChoreographerFrameCallbackData* data, size_t index) {
@@ -680,8 +668,8 @@
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
"Data is only valid in callback");
- LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
- return frameCallbackData->frameTimelines[index].deadlineNanos;
+ LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
+ return frameCallbackData->frameTimelines[index].deadlineTimestamp;
}
AChoreographer* AChoreographer_create() {
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 2db9992..93e7239 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -133,7 +133,6 @@
int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) {
static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
- static_assert(static_cast<int>(STANDARD_SHIFT) == static_cast<int>(HAL_DATASPACE_STANDARD_SHIFT));
static_assert(static_cast<int>(STANDARD_MASK) == static_cast<int>(HAL_DATASPACE_STANDARD_MASK));
static_assert(static_cast<int>(STANDARD_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_STANDARD_UNSPECIFIED));
static_assert(static_cast<int>(STANDARD_BT709) == static_cast<int>(HAL_DATASPACE_STANDARD_BT709));
@@ -145,7 +144,6 @@
static_assert(static_cast<int>(STANDARD_FILM) == static_cast<int>(HAL_DATASPACE_STANDARD_FILM));
static_assert(static_cast<int>(STANDARD_DCI_P3) == static_cast<int>(HAL_DATASPACE_STANDARD_DCI_P3));
static_assert(static_cast<int>(STANDARD_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_STANDARD_ADOBE_RGB));
- static_assert(static_cast<int>(TRANSFER_SHIFT) == static_cast<int>(HAL_DATASPACE_TRANSFER_SHIFT));
static_assert(static_cast<int>(TRANSFER_MASK) == static_cast<int>(HAL_DATASPACE_TRANSFER_MASK));
static_assert(static_cast<int>(TRANSFER_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_TRANSFER_UNSPECIFIED));
static_assert(static_cast<int>(TRANSFER_LINEAR) == static_cast<int>(HAL_DATASPACE_TRANSFER_LINEAR));
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 612fb39..a299488 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -56,9 +56,7 @@
* Defines the chromaticity coordinates of the source primaries in terms of
* the CIE 1931 definition of x and y specified in ISO 11664-1.
*/
- STANDARD_SHIFT = 16,
-
- STANDARD_MASK = 63 << 16, // 63 << STANDARD_SHIFT = 0x3F
+ STANDARD_MASK = 63 << 16,
/**
* Chromacity coordinates are unknown or are determined by the application.
@@ -73,7 +71,7 @@
* For all other formats standard is undefined, and implementations should use
* an appropriate standard for the data represented.
*/
- STANDARD_UNSPECIFIED = 0 << 16, // STANDARD_SHIFT
+ STANDARD_UNSPECIFIED = 0 << 16,
/**
* Primaries: x y
@@ -85,7 +83,7 @@
* Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
* for RGB conversion.
*/
- STANDARD_BT709 = 1 << 16, // 1 << STANDARD_SHIFT
+ STANDARD_BT709 = 1 << 16,
/**
* Primaries: x y
@@ -99,7 +97,7 @@
* to minimize the color shift into RGB space that uses BT.709
* primaries.
*/
- STANDARD_BT601_625 = 2 << 16, // 2 << STANDARD_SHIFT,
+ STANDARD_BT601_625 = 2 << 16,
/**
* Primaries: x y
@@ -111,7 +109,7 @@
* Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
* for RGB conversion.
*/
- STANDARD_BT601_625_UNADJUSTED = 3 << 16, // 3 << STANDARD_SHIFT
+ STANDARD_BT601_625_UNADJUSTED = 3 << 16,
/**
* Primaries: x y
@@ -125,7 +123,7 @@
* to minimize the color shift into RGB space that uses BT.709
* primaries.
*/
- STANDARD_BT601_525 = 4 << 16, // 4 << STANDARD_SHIFT
+ STANDARD_BT601_525 = 4 << 16,
/**
* Primaries: x y
@@ -137,7 +135,7 @@
* Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
* for RGB conversion (as in SMPTE 240M).
*/
- STANDARD_BT601_525_UNADJUSTED = 5 << 16, // 5 << STANDARD_SHIFT
+ STANDARD_BT601_525_UNADJUSTED = 5 << 16,
/**
* Primaries: x y
@@ -149,7 +147,7 @@
* Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
* for RGB conversion.
*/
- STANDARD_BT2020 = 6 << 16, // 6 << STANDARD_SHIFT
+ STANDARD_BT2020 = 6 << 16,
/**
* Primaries: x y
@@ -161,7 +159,7 @@
* Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
* for RGB conversion using the linear domain.
*/
- STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, // 7 << STANDARD_SHIFT
+ STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16,
/**
* Primaries: x y
@@ -173,7 +171,7 @@
* Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
* for RGB conversion.
*/
- STANDARD_BT470M = 8 << 16, // 8 << STANDARD_SHIFT
+ STANDARD_BT470M = 8 << 16,
/**
* Primaries: x y
@@ -185,7 +183,7 @@
* Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
* for RGB conversion.
*/
- STANDARD_FILM = 9 << 16, // 9 << STANDARD_SHIFT
+ STANDARD_FILM = 9 << 16,
/**
* SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
@@ -195,7 +193,7 @@
* red 0.680 0.320
* white (D65) 0.3127 0.3290
*/
- STANDARD_DCI_P3 = 10 << 16, // 10 << STANDARD_SHIFT
+ STANDARD_DCI_P3 = 10 << 16,
/**
* Adobe RGB
@@ -205,7 +203,7 @@
* red 0.640 0.330
* white (D65) 0.3127 0.3290
*/
- STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
+ STANDARD_ADOBE_RGB = 11 << 16,
/**
* Transfer aspect
@@ -220,9 +218,7 @@
* component. Implementation may apply the transfer function in RGB space
* for all pixel formats if desired.
*/
- TRANSFER_SHIFT = 22,
-
- TRANSFER_MASK = 31 << 22, // 31 << TRANSFER_SHIFT = 0x1F
+ TRANSFER_MASK = 31 << 22,
/**
* Transfer characteristics are unknown or are determined by the
@@ -236,7 +232,7 @@
* For all other formats transfer function is undefined, and implementations
* should use an appropriate standard for the data represented.
*/
- TRANSFER_UNSPECIFIED = 0 << 22, // 0 << TRANSFER_SHIFT
+ TRANSFER_UNSPECIFIED = 0 << 22,
/**
* Transfer characteristic curve:
@@ -244,7 +240,7 @@
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*/
- TRANSFER_LINEAR = 1 << 22, // 1 << TRANSFER_SHIFT
+ TRANSFER_LINEAR = 1 << 22,
/**
* Transfer characteristic curve:
@@ -254,7 +250,7 @@
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*/
- TRANSFER_SRGB = 2 << 22, // 2 << TRANSFER_SHIFT
+ TRANSFER_SRGB = 2 << 22,
/**
* BT.601 525, BT.601 625, BT.709, BT.2020
@@ -265,7 +261,7 @@
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*/
- TRANSFER_SMPTE_170M = 3 << 22, // 3 << TRANSFER_SHIFT
+ TRANSFER_SMPTE_170M = 3 << 22,
/**
* Assumed display gamma 2.2.
@@ -275,7 +271,7 @@
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*/
- TRANSFER_GAMMA2_2 = 4 << 22, // 4 << TRANSFER_SHIFT
+ TRANSFER_GAMMA2_2 = 4 << 22,
/**
* display gamma 2.6.
@@ -285,7 +281,7 @@
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*/
- TRANSFER_GAMMA2_6 = 5 << 22, // 5 << TRANSFER_SHIFT
+ TRANSFER_GAMMA2_6 = 5 << 22,
/**
* display gamma 2.8.
@@ -295,7 +291,7 @@
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*/
- TRANSFER_GAMMA2_8 = 6 << 22, // 6 << TRANSFER_SHIFT
+ TRANSFER_GAMMA2_8 = 6 << 22,
/**
* SMPTE ST 2084 (Dolby Perceptual Quantizer)
@@ -311,7 +307,7 @@
* L = 1 corresponds to 10000 cd/m2
* E - corresponding electrical signal
*/
- TRANSFER_ST2084 = 7 << 22, // 7 << TRANSFER_SHIFT
+ TRANSFER_ST2084 = 7 << 22,
/**
* ARIB STD-B67 Hybrid Log Gamma
@@ -327,7 +323,7 @@
* to reference white level of 100 cd/m2
* E - corresponding electrical signal
*/
- TRANSFER_HLG = 8 << 22, // 8 << TRANSFER_SHIFT
+ TRANSFER_HLG = 8 << 22,
/**
* Range aspect
@@ -335,9 +331,7 @@
* Defines the range of values corresponding to the unit range of 0-1.
* This is defined for YCbCr only, but can be expanded to RGB space.
*/
- RANGE_SHIFT = 27,
-
- RANGE_MASK = 7 << 27, // 7 << RANGE_SHIFT = 0x7
+ RANGE_MASK = 7 << 27,
/**
* Range is unknown or are determined by the application. Implementations
@@ -350,13 +344,13 @@
* For all other formats range is undefined, and implementations should use
* an appropriate range for the data represented.
*/
- RANGE_UNSPECIFIED = 0 << 27, // 0 << RANGE_SHIFT = 0x0
+ RANGE_UNSPECIFIED = 0 << 27,
/**
* Full range uses all values for Y, Cb and Cr from
* 0 to 2^b-1, where b is the bit depth of the color format.
*/
- RANGE_FULL = 1 << 27, // 1 << RANGE_SHIFT = 0x8000000
+ RANGE_FULL = 1 << 27,
/**
* Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
@@ -371,7 +365,7 @@
* Luma (Y) samples should range from 64 to 940, inclusive
* Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
*/
- RANGE_LIMITED = 2 << 27, // 2 << RANGE_SHIFT = 0x10000000
+ RANGE_LIMITED = 2 << 27,
/**
* Extended range is used for scRGB. Intended for use with
@@ -380,7 +374,7 @@
* color outside the sRGB gamut.
* Used to blend / merge multiple dataspaces on a single display.
*/
- RANGE_EXTENDED = 3 << 27, // 3 << RANGE_SHIFT = 0x18000000
+ RANGE_EXTENDED = 3 << 27,
/**
* scRGB linear encoding:
diff --git a/libs/permission/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
index e3d705f..abcd527 100644
--- a/libs/permission/include/binder/AppOpsManager.h
+++ b/libs/permission/include/binder/AppOpsManager.h
@@ -147,7 +147,8 @@
OP_ACTIVITY_RECOGNITION_SOURCE = 113,
OP_BLUETOOTH_ADVERTISE = 114,
OP_RECORD_INCOMING_PHONE_AUDIO = 115,
- _NUM_OP = 116
+ OP_NEARBY_WIFI_DEVICES = 116,
+ _NUM_OP = 117
};
AppOpsManager();
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 570c7bc..336ff68 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -93,7 +93,7 @@
"skia/debug/CommonPool.cpp",
"skia/debug/SkiaCapture.cpp",
"skia/debug/SkiaMemoryReporter.cpp",
- "skia/filters/BlurFilter.cpp",
+ "skia/filters/KawaseBlurFilter.cpp",
"skia/filters/LinearEffect.cpp",
"skia/filters/StretchShaderFactory.cpp"
],
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 2174df5..a9ea690 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -96,7 +96,7 @@
}
std::future<RenderEngineResult> RenderEngine::drawLayers(
- const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence) {
const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 2375cb7..22dd866 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1080,7 +1080,7 @@
void GLESRenderEngine::drawLayersInternal(
const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
- const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence) {
ATRACE_CALL();
@@ -1110,10 +1110,10 @@
std::unique_ptr<BindNativeBufferAsFramebuffer> fbo;
// Gathering layers that requested blur, we'll need them to decide when to render to an
// offscreen buffer, and when to render to the native buffer.
- std::deque<const LayerSettings*> blurLayers;
+ std::deque<const LayerSettings> blurLayers;
if (CC_LIKELY(mBlurFilter != nullptr)) {
- for (auto layer : layers) {
- if (layer->backgroundBlurRadius > 0) {
+ for (const auto& layer : layers) {
+ if (layer.backgroundBlurRadius > 0) {
blurLayers.push_back(layer);
}
}
@@ -1137,7 +1137,7 @@
} else {
setViewportAndProjection(display.physicalDisplay, display.clip);
auto status =
- mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius);
+ mBlurFilter->setAsDrawTarget(display, blurLayers.front().backgroundBlurRadius);
if (status != NO_ERROR) {
ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
@@ -1167,7 +1167,7 @@
.setTexCoords(2 /* size */)
.setCropCoords(2 /* size */)
.build();
- for (auto const layer : layers) {
+ for (const auto& layer : layers) {
if (blurLayers.size() > 0 && blurLayers.front() == layer) {
blurLayers.pop_front();
@@ -1193,7 +1193,7 @@
// There's still something else to blur, so let's keep rendering to our FBO
// instead of to the display.
status = mBlurFilter->setAsDrawTarget(display,
- blurLayers.front()->backgroundBlurRadius);
+ blurLayers.front().backgroundBlurRadius);
}
if (status != NO_ERROR) {
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
@@ -1214,42 +1214,42 @@
}
// Ensure luminance is at least 100 nits to avoid div-by-zero
- const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits);
+ const float maxLuminance = std::max(100.f, layer.source.buffer.maxLuminanceNits);
mState.maxMasteringLuminance = maxLuminance;
mState.maxContentLuminance = maxLuminance;
- mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform;
+ mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
- const FloatRect bounds = layer->geometry.boundaries;
+ const FloatRect bounds = layer.geometry.boundaries;
Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
position[0] = vec2(bounds.left, bounds.top);
position[1] = vec2(bounds.left, bounds.bottom);
position[2] = vec2(bounds.right, bounds.bottom);
position[3] = vec2(bounds.right, bounds.top);
- setupLayerCropping(*layer, mesh);
- setColorTransform(layer->colorTransform);
+ setupLayerCropping(layer, mesh);
+ setColorTransform(layer.colorTransform);
bool usePremultipliedAlpha = true;
bool disableTexture = true;
bool isOpaque = false;
- if (layer->source.buffer.buffer != nullptr) {
+ if (layer.source.buffer.buffer != nullptr) {
disableTexture = false;
- isOpaque = layer->source.buffer.isOpaque;
+ isOpaque = layer.source.buffer.isOpaque;
- sp<GraphicBuffer> gBuf = layer->source.buffer.buffer->getBuffer();
+ sp<GraphicBuffer> gBuf = layer.source.buffer.buffer->getBuffer();
validateInputBufferUsage(gBuf);
- bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf,
- layer->source.buffer.fence);
+ bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
+ layer.source.buffer.fence);
- usePremultipliedAlpha = layer->source.buffer.usePremultipliedAlpha;
- Texture texture(Texture::TEXTURE_EXTERNAL, layer->source.buffer.textureName);
- mat4 texMatrix = layer->source.buffer.textureTransform;
+ usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
+ Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
+ mat4 texMatrix = layer.source.buffer.textureTransform;
texture.setMatrix(texMatrix.asArray());
- texture.setFiltering(layer->source.buffer.useTextureFiltering);
+ texture.setFiltering(layer.source.buffer.useTextureFiltering);
texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
- setSourceY410BT2020(layer->source.buffer.isY410BT2020);
+ setSourceY410BT2020(layer.source.buffer.isY410BT2020);
renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
texCoords[0] = vec2(0.0, 0.0);
@@ -1264,32 +1264,32 @@
}
}
- const half3 solidColor = layer->source.solidColor;
- const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer->alpha);
+ const half3 solidColor = layer.source.solidColor;
+ const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
// Buffer sources will have a black solid color ignored in the shader,
// so in that scenario the solid color passed here is arbitrary.
setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
- layer->geometry.roundedCornersRadius);
- if (layer->disableBlending) {
+ layer.geometry.roundedCornersRadius);
+ if (layer.disableBlending) {
glDisable(GL_BLEND);
}
- setSourceDataSpace(layer->sourceDataspace);
+ setSourceDataSpace(layer.sourceDataspace);
- if (layer->shadow.length > 0.0f) {
- handleShadow(layer->geometry.boundaries, layer->geometry.roundedCornersRadius,
- layer->shadow);
+ if (layer.shadow.length > 0.0f) {
+ handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius,
+ layer.shadow);
}
// We only want to do a special handling for rounded corners when having rounded corners
// is the only reason it needs to turn on blending, otherwise, we handle it like the
// usual way since it needs to turn on blending anyway.
- else if (layer->geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
- handleRoundedCorners(display, *layer, mesh);
+ else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+ handleRoundedCorners(display, layer, mesh);
} else {
drawMesh(mesh);
}
// Cleanup if there's a buffer source
- if (layer->source.buffer.buffer != nullptr) {
+ if (layer.source.buffer.buffer != nullptr) {
disableBlending();
setSourceY410BT2020(false);
disableTexturing();
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index c4adfdf..1d7c2ca 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -104,7 +104,7 @@
bool canSkipPostRenderCleanup() const override;
void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
+ const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer,
const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 701c1f2..b9cc648 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -160,7 +160,7 @@
// @return A future object of RenderEngineResult struct indicating whether
// drawing was successful in async mode.
virtual std::future<RenderEngineResult> drawLayers(
- const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence);
@@ -231,7 +231,7 @@
virtual void drawLayersInternal(
const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
- const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence) = 0;
};
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index a7e6809..248bd65 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -49,12 +49,12 @@
MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool());
MOCK_METHOD5(drawLayers,
std::future<RenderEngineResult>(const DisplaySettings&,
- const std::vector<const LayerSettings*>&,
+ const std::vector<LayerSettings>&,
const std::shared_ptr<ExternalTexture>&,
const bool, base::unique_fd&&));
MOCK_METHOD6(drawLayersInternal,
void(const std::shared_ptr<std::promise<RenderEngineResult>>&&,
- const DisplaySettings&, const std::vector<const LayerSettings*>&,
+ const DisplaySettings&, const std::vector<LayerSettings>&,
const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&));
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index c4fa1bb..b18a872 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -95,7 +95,7 @@
.alpha = 1,
};
- auto layers = std::vector<const LayerSettings*>{&layer, &caster};
+ auto layers = std::vector<LayerSettings>{layer, caster};
// Four combinations of settings are used (two transforms here, and drawShadowLayers is
// called with two different destination data spaces) They're all rounded rect.
// Three of these are cache misses that generate new shaders.
@@ -140,7 +140,7 @@
}},
};
- auto layers = std::vector<const LayerSettings*>{&layer};
+ auto layers = std::vector<LayerSettings>{layer};
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
layer.sourceDataspace = dataspace;
// Cache shaders for both rects and round rects.
@@ -176,7 +176,7 @@
.alpha = 0.5,
};
- auto layers = std::vector<const LayerSettings*>{&layer};
+ auto layers = std::vector<LayerSettings>{layer};
for (auto transform : {mat4(), kScaleAndTranslate}) {
layer.geometry.positionTransform = transform;
for (float roundedCornersRadius : {0.0f, 50.f}) {
@@ -201,7 +201,7 @@
.skipContentDraw = true,
};
- auto layers = std::vector<const LayerSettings*>{&layer};
+ auto layers = std::vector<LayerSettings>{layer};
// Different blur code is invoked for radii less and greater than 30 pixels
for (int radius : {9, 60}) {
layer.backgroundBlurRadius = radius;
@@ -242,7 +242,7 @@
},
};
- auto layers = std::vector<const LayerSettings*>{&layer};
+ auto layers = std::vector<LayerSettings>{layer};
for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
layer.source = pixelSource;
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
@@ -289,7 +289,7 @@
};
- auto layers = std::vector<const LayerSettings*>{&layer};
+ auto layers = std::vector<LayerSettings>{layer};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd());
}
@@ -317,7 +317,7 @@
};
- auto layers = std::vector<const LayerSettings*>{&layer};
+ auto layers = std::vector<LayerSettings>{layer};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd());
}
@@ -429,7 +429,7 @@
LayerSettings layer{
.source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)},
};
- auto layers = std::vector<const LayerSettings*>{&layer};
+ auto layers = std::vector<LayerSettings>{layer};
// call get() to make it synchronous
renderengine
->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd())
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index cb686a6..e6fb94d 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -53,6 +53,7 @@
#include "SkBlendMode.h"
#include "SkImageInfo.h"
#include "filters/BlurFilter.h"
+#include "filters/KawaseBlurFilter.h"
#include "filters/LinearEffect.h"
#include "log/log_main.h"
#include "skia/debug/SkiaCapture.h"
@@ -328,7 +329,7 @@
if (args.supportsBackgroundBlur) {
ALOGD("Background Blurs Enabled");
- mBlurFilter = new BlurFilter();
+ mBlurFilter = new KawaseBlurFilter();
}
mCapture = std::make_unique<SkiaCapture>();
}
@@ -610,17 +611,18 @@
AutoBackendTexture::CleanupManager& mMgr;
};
-sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(
- sk_sp<SkShader> shader,
- const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha,
- bool requiresLinearEffect) {
- const auto stretchEffect = layer->stretchEffect;
+sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader,
+ const LayerSettings& layer,
+ const DisplaySettings& display,
+ bool undoPremultipliedAlpha,
+ bool requiresLinearEffect) {
+ const auto stretchEffect = layer.stretchEffect;
// The given surface will be stretched by HWUI via matrix transformation
// which gets similar results for most surfaces
// Determine later on if we need to leverage the stertch shader within
// surface flinger
if (stretchEffect.hasEffect()) {
- const auto targetBuffer = layer->source.buffer.buffer;
+ const auto targetBuffer = layer.source.buffer.buffer;
const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
if (graphicBuffer && shader) {
shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
@@ -629,7 +631,7 @@
if (requiresLinearEffect) {
const ui::Dataspace inputDataspace =
- mUseColorManagement ? layer->sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR;
+ mUseColorManagement ? layer.sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR;
const ui::Dataspace outputDataspace =
mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR;
@@ -645,13 +647,13 @@
} else {
runtimeEffect = effectIter->second;
}
- float maxLuminance = layer->source.buffer.maxLuminanceNits;
+ float maxLuminance = layer.source.buffer.maxLuminanceNits;
// If the buffer doesn't have a max luminance, treat it as SDR & use the display's SDR
// white point
if (maxLuminance <= 0.f) {
maxLuminance = display.sdrWhitePointNits;
}
- return createLinearEffectShader(shader, effect, runtimeEffect, layer->colorTransform,
+ return createLinearEffectShader(shader, effect, runtimeEffect, layer.colorTransform,
display.maxLuminance, maxLuminance);
}
return shader;
@@ -729,7 +731,7 @@
void SkiaGLRenderEngine::drawLayersInternal(
const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
- const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
base::unique_fd&& bufferFence) {
ATRACE_NAME("SkiaGL::drawLayers");
@@ -801,11 +803,11 @@
if (!layerHasBlur(layer, ctModifiesAlpha)) {
continue;
}
- if (layer->backgroundBlurRadius > 0 &&
- layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) {
+ if (layer.backgroundBlurRadius > 0 &&
+ layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) {
requiresCompositionLayer = true;
}
- for (auto region : layer->blurRegions) {
+ for (auto region : layer.blurRegions) {
if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) {
requiresCompositionLayer = true;
}
@@ -813,7 +815,7 @@
if (requiresCompositionLayer) {
activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
- blurCompositionLayer = layer;
+ blurCompositionLayer = &layer;
break;
}
}
@@ -825,11 +827,11 @@
initCanvas(canvas, display);
for (const auto& layer : layers) {
- ATRACE_FORMAT("DrawLayer: %s", layer->name.c_str());
+ ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str());
if (kPrintLayerSettings) {
std::stringstream ls;
- PrintTo(*layer, &ls);
+ PrintTo(layer, &ls);
auto debugs = ls.str();
int pos = 0;
while (pos < debugs.size()) {
@@ -839,7 +841,7 @@
}
sk_sp<SkImage> blurInput;
- if (blurCompositionLayer == layer) {
+ if (blurCompositionLayer == &layer) {
LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
@@ -878,17 +880,17 @@
if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
// Record the name of the layer if the capture is running.
std::stringstream layerSettings;
- PrintTo(*layer, &layerSettings);
+ PrintTo(layer, &layerSettings);
// Store the LayerSettings in additional information.
- canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(),
+ canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(),
SkData::MakeWithCString(layerSettings.str().c_str()));
}
// Layers have a local transform that should be applied to them
- canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());
+ canvas->concat(getSkM44(layer.geometry.positionTransform).asM33());
const auto [bounds, roundRectClip] =
- getBoundsAndClip(layer->geometry.boundaries, layer->geometry.roundedCornersCrop,
- layer->geometry.roundedCornersRadius);
+ getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
+ layer.geometry.roundedCornersRadius);
if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
@@ -909,20 +911,19 @@
// TODO(b/182216890): Filter out empty layers earlier
if (blurRect.width() > 0 && blurRect.height() > 0) {
- if (layer->backgroundBlurRadius > 0) {
+ if (layer.backgroundBlurRadius > 0) {
ATRACE_NAME("BackgroundBlur");
- auto blurredImage =
- mBlurFilter->generate(grContext, layer->backgroundBlurRadius, blurInput,
- blurRect);
+ auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius,
+ blurInput, blurRect);
- cachedBlurs[layer->backgroundBlurRadius] = blurredImage;
+ cachedBlurs[layer.backgroundBlurRadius] = blurredImage;
- mBlurFilter->drawBlurRegion(canvas, bounds, layer->backgroundBlurRadius, 1.0f,
+ mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f,
blurRect, blurredImage, blurInput);
}
- canvas->concat(getSkM44(layer->blurRegionTransform).asM33());
- for (auto region : layer->blurRegions) {
+ canvas->concat(getSkM44(layer.blurRegionTransform).asM33());
+ for (auto region : layer.blurRegions) {
if (cachedBlurs[region.blurRadius] == nullptr) {
ATRACE_NAME("BlurRegion");
cachedBlurs[region.blurRadius] =
@@ -937,19 +938,18 @@
}
}
- if (layer->shadow.length > 0) {
+ if (layer.shadow.length > 0) {
// This would require a new parameter/flag to SkShadowUtils::DrawShadow
- LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow");
+ LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
SkRRect shadowBounds, shadowClip;
- if (layer->geometry.boundaries == layer->shadow.boundaries) {
+ if (layer.geometry.boundaries == layer.shadow.boundaries) {
shadowBounds = bounds;
shadowClip = roundRectClip;
} else {
std::tie(shadowBounds, shadowClip) =
- getBoundsAndClip(layer->shadow.boundaries,
- layer->geometry.roundedCornersCrop,
- layer->geometry.roundedCornersRadius);
+ getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop,
+ layer.geometry.roundedCornersRadius);
}
// Technically, if bounds is a rect and roundRectClip is not empty,
@@ -960,18 +960,18 @@
// looks more like the intent.
const auto& rrect =
shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
- drawShadow(canvas, rrect, layer->shadow);
+ drawShadow(canvas, rrect, layer.shadow);
}
- const bool requiresLinearEffect = layer->colorTransform != mat4() ||
+ const bool requiresLinearEffect = layer.colorTransform != mat4() ||
(mUseColorManagement &&
- needsToneMapping(layer->sourceDataspace, display.outputDataspace)) ||
+ needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
(display.sdrWhitePointNits > 0.f &&
display.sdrWhitePointNits != display.maxLuminance);
// quick abort from drawing the remaining portion of the layer
- if (layer->skipContentDraw ||
- (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending &&
+ if (layer.skipContentDraw ||
+ (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending &&
(!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) {
continue;
}
@@ -981,13 +981,13 @@
// management is a no-op.
const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect)
? dstDataspace
- : layer->sourceDataspace;
+ : layer.sourceDataspace;
SkPaint paint;
- if (layer->source.buffer.buffer) {
+ if (layer.source.buffer.buffer) {
ATRACE_NAME("DrawImage");
- validateInputBufferUsage(layer->source.buffer.buffer->getBuffer());
- const auto& item = layer->source.buffer;
+ validateInputBufferUsage(layer.source.buffer.buffer->getBuffer());
+ const auto& item = layer.source.buffer;
std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
if (const auto& iter = cache.find(item.buffer->getBuffer()->getId());
@@ -1006,8 +1006,8 @@
// if the layer's buffer has a fence, then we must must respect the fence prior to using
// the buffer.
- if (layer->source.buffer.fence != nullptr) {
- waitFence(layer->source.buffer.fence->get());
+ if (layer.source.buffer.fence != nullptr) {
+ waitFence(layer.source.buffer.fence->get());
}
// isOpaque means we need to ignore the alpha in the image,
@@ -1051,7 +1051,7 @@
sk_sp<SkShader> shader;
- if (layer->source.buffer.useTextureFiltering) {
+ if (layer.source.buffer.useTextureFiltering) {
shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
SkSamplingOptions(
{SkFilterMode::kLinear, SkMipmapMode::kNone}),
@@ -1069,21 +1069,21 @@
paint.setShader(createRuntimeEffectShader(shader, layer, display,
!item.isOpaque && item.usePremultipliedAlpha,
requiresLinearEffect));
- paint.setAlphaf(layer->alpha);
+ paint.setAlphaf(layer.alpha);
} else {
ATRACE_NAME("DrawColor");
- const auto color = layer->source.solidColor;
+ const auto color = layer.source.solidColor;
sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
.fG = color.g,
.fB = color.b,
- .fA = layer->alpha},
+ .fA = layer.alpha},
toSkColorSpace(layerDataspace));
paint.setShader(createRuntimeEffectShader(shader, layer, display,
/* undoPremultipliedAlpha */ false,
requiresLinearEffect));
}
- if (layer->disableBlending) {
+ if (layer.disableBlending) {
paint.setBlendMode(SkBlendMode::kSrc);
}
@@ -1251,13 +1251,13 @@
return {SkRRect::MakeRect(bounds), clip};
}
-inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer,
+inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings& layer,
bool colorTransformModifiesAlpha) {
- if (layer->backgroundBlurRadius > 0 || layer->blurRegions.size()) {
+ if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) {
// return false if the content is opaque and would therefore occlude the blur
- const bool opaqueContent = !layer->source.buffer.buffer || layer->source.buffer.isOpaque;
- const bool opaqueAlpha = layer->alpha == 1.0f && !colorTransformModifiesAlpha;
- return layer->skipContentDraw || !(opaqueContent && opaqueAlpha);
+ const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque;
+ const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha;
+ return layer.skipContentDraw || !(opaqueContent && opaqueAlpha);
}
return false;
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index e010c35..74ce651 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -74,7 +74,7 @@
bool canSkipPostRenderCleanup() const override;
void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
+ const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer,
const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
@@ -92,7 +92,7 @@
inline SkRect getSkRect(const Rect& layer);
inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds,
const FloatRect& crop, float cornerRadius);
- inline bool layerHasBlur(const LayerSettings* layer, bool colorTransformModifiesAlpha);
+ inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha);
inline SkColor getSkColor(const vec4& color);
inline SkM44 getSkM44(const mat4& matrix);
inline SkPoint3 getSkPoint3(const vec3& vector);
@@ -108,8 +108,7 @@
const ShadowSettings& shadowSettings);
// If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
// Otherwise it returns the input shader.
- sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader,
- const LayerSettings* layer,
+ sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings& layer,
const DisplaySettings& display,
bool undoPremultipliedAlpha,
bool requiresLinearEffect);
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index f61653b..eb65e83 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -55,7 +55,7 @@
virtual void drawLayersInternal(
const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
- const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence) override {
resultPromise->set_value({NO_ERROR, base::unique_fd()});
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 7110018..1beadee 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -27,29 +27,22 @@
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(){}
+ 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 +54,10 @@
* @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);
-
-private:
- sk_sp<SkRuntimeEffect> mBlurEffect;
- sk_sp<SkRuntimeEffect> mMixEffect;
+ virtual 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) = 0;
};
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
similarity index 78%
rename from libs/renderengine/skia/filters/BlurFilter.cpp
rename to libs/renderengine/skia/filters/KawaseBlurFilter.cpp
index 2b6833e..e3a0e58 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.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.
@@ -16,7 +16,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "BlurFilter.h"
+#include "KawaseBlurFilter.h"
#include <SkCanvas.h>
#include <SkData.h>
#include <SkPaint.h>
@@ -32,23 +32,17 @@
namespace renderengine {
namespace skia {
-BlurFilter::BlurFilter() {
+KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() {
SkString blurString(R"(
uniform shader child;
- uniform float2 in_blurOffset;
- uniform float2 in_maxSizeXY;
+ uniform float in_blurOffset;
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)));
-
+ 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);
}
)");
@@ -76,8 +70,9 @@
mMixEffect = std::move(mixEffect);
}
-sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
- const sk_sp<SkImage> input, const SkRect& blurRect) const {
+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.
@@ -89,9 +84,6 @@
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.
@@ -103,20 +95,15 @@
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};
+ 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++) {
- 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};
+ blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale;
tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
}
@@ -139,7 +126,7 @@
return matrix;
}
-void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion,
+void KawaseBlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion,
const uint32_t blurRadius, const float blurAlpha,
const SkRect& blurRect, sk_sp<SkImage> blurredImage,
sk_sp<SkImage> input) {
diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.h b/libs/renderengine/skia/filters/KawaseBlurFilter.h
new file mode 100644
index 0000000..d2731e3
--- /dev/null
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.h
@@ -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.
+ */
+
+#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;
+
+ /**
+ * Draw the blurred content (from the generate method) into the canvas.
+ * @param canvas is the destination/output for the blur
+ * @param effectRegion the RoundRect in canvas coordinates that determines the blur coverage
+ * @param blurRadius radius of the blur used to determine the intensity of the crossfade effect
+ * @param blurAlpha alpha value applied to the effectRegion when the blur is drawn
+ * @param blurRect bounds of the blurredImage translated into canvas coordinates
+ * @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) override;
+
+private:
+ sk_sp<SkRuntimeEffect> mBlurEffect;
+ sk_sp<SkRuntimeEffect> mMixEffect;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 694bda6..c2c05f4 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -417,10 +417,11 @@
DEFAULT_DISPLAY_HEIGHT - DEFAULT_DISPLAY_OFFSET);
}
- void invokeDraw(renderengine::DisplaySettings settings,
- std::vector<const renderengine::LayerSettings*> layers) {
+ void invokeDraw(const renderengine::DisplaySettings& settings,
+ const std::vector<renderengine::LayerSettings>& layers) {
std::future<renderengine::RenderEngineResult> result =
mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
+
ASSERT_TRUE(result.valid());
auto [status, fence] = result.get();
@@ -436,7 +437,7 @@
void drawEmptyLayers() {
renderengine::DisplaySettings settings;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
invokeDraw(settings, layers);
}
@@ -629,7 +630,7 @@
settings.clip = fullscreenRect();
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -637,7 +638,7 @@
SourceVariant::fillColor(layer, r, g, b, this);
layer.alpha = a;
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -673,7 +674,7 @@
settings.physicalDisplay = offsetRect();
settings.clip = offsetRectAtZero();
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -681,7 +682,7 @@
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -708,7 +709,7 @@
settings.clip = Rect(2, 2);
settings.orientation = orientationFlag;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layerOne;
layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -731,9 +732,9 @@
SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this);
layerThree.alpha = 1.0f;
- layers.push_back(&layerOne);
- layers.push_back(&layerTwo);
- layers.push_back(&layerThree);
+ layers.push_back(layerOne);
+ layers.push_back(layerTwo);
+ layers.push_back(layerThree);
invokeDraw(settings, layers);
}
@@ -810,7 +811,7 @@
settings.clip = Rect(2, 2);
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -821,7 +822,7 @@
layer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
layer.alpha = 1.0f;
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -843,7 +844,7 @@
settings.clip = Rect(1, 1);
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -860,7 +861,7 @@
layer.alpha = 1.0f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -877,7 +878,7 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
@@ -890,7 +891,7 @@
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -908,7 +909,7 @@
settings.clip = fullscreenRect();
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -918,7 +919,7 @@
SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -949,14 +950,14 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings backgroundLayer;
backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this);
backgroundLayer.alpha = 1.0f;
- layers.push_back(&backgroundLayer);
+ layers.emplace_back(backgroundLayer);
renderengine::LayerSettings leftLayer;
leftLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -964,7 +965,7 @@
Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect();
SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this);
leftLayer.alpha = 1.0f;
- layers.push_back(&leftLayer);
+ layers.emplace_back(leftLayer);
renderengine::LayerSettings blurLayer;
blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -972,7 +973,7 @@
blurLayer.backgroundBlurRadius = blurRadius;
SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
blurLayer.alpha = 0;
- layers.push_back(&blurLayer);
+ layers.emplace_back(blurLayer);
invokeDraw(settings, layers);
@@ -994,14 +995,14 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings backgroundLayer;
backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
SourceVariant::fillColor(backgroundLayer, 1.0f, 0.0f, 0.0f, this);
backgroundLayer.alpha = 1.0f;
- layers.push_back(&backgroundLayer);
+ layers.push_back(backgroundLayer);
renderengine::LayerSettings blurLayer;
blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1009,7 +1010,7 @@
blurLayer.backgroundBlurRadius = blurRadius;
SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
blurLayer.alpha = 0;
- layers.push_back(&blurLayer);
+ layers.push_back(blurLayer);
invokeDraw(settings, layers);
@@ -1026,7 +1027,7 @@
settings.clip = fullscreenRect();
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layersFirst;
+ std::vector<renderengine::LayerSettings> layersFirst;
renderengine::LayerSettings layerOne;
layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1035,14 +1036,14 @@
SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
layerOne.alpha = 0.2;
- layersFirst.push_back(&layerOne);
+ layersFirst.push_back(layerOne);
invokeDraw(settings, layersFirst);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
0, 0, 0, 0);
- std::vector<const renderengine::LayerSettings*> layersSecond;
+ std::vector<renderengine::LayerSettings> layersSecond;
renderengine::LayerSettings layerTwo;
layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
layerTwo.geometry.boundaries =
@@ -1051,7 +1052,7 @@
SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
layerTwo.alpha = 1.0f;
- layersSecond.push_back(&layerTwo);
+ layersSecond.push_back(layerTwo);
invokeDraw(settings, layersSecond);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
@@ -1066,7 +1067,7 @@
settings.clip = Rect(1, 1);
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1102,7 +1103,7 @@
layer.alpha = 1.0f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -1118,7 +1119,7 @@
// Here logical space is 1x1
settings.clip = Rect(1, 1);
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
const auto buf = allocateSourceBuffer(1, 1);
@@ -1141,7 +1142,7 @@
layer.alpha = 0.5f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -1157,7 +1158,7 @@
// Here logical space is 1x1
settings.clip = Rect(1, 1);
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
const auto buf = allocateSourceBuffer(1, 1);
@@ -1180,7 +1181,7 @@
layer.alpha = 0.5f;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -1199,7 +1200,7 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
// add background layer
renderengine::LayerSettings bgLayer;
@@ -1208,7 +1209,7 @@
ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
backgroundColor.b / 255.0f, this);
bgLayer.alpha = backgroundColor.a / 255.0f;
- layers.push_back(&bgLayer);
+ layers.push_back(bgLayer);
// add shadow layer
renderengine::LayerSettings shadowLayer;
@@ -1216,14 +1217,14 @@
shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries;
shadowLayer.alpha = castingLayer.alpha;
shadowLayer.shadow = shadow;
- layers.push_back(&shadowLayer);
+ layers.push_back(shadowLayer);
// add layer casting the shadow
renderengine::LayerSettings layer = castingLayer;
layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f,
casterColor.b / 255.0f, this);
- layers.push_back(&layer);
+ layers.push_back(layer);
invokeDraw(settings, layers);
}
@@ -1236,7 +1237,7 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
// add background layer
renderengine::LayerSettings bgLayer;
@@ -1245,7 +1246,7 @@
ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
backgroundColor.b / 255.0f, this);
bgLayer.alpha = backgroundColor.a / 255.0f;
- layers.push_back(&bgLayer);
+ layers.push_back(bgLayer);
// add shadow layer
renderengine::LayerSettings shadowLayer;
@@ -1255,7 +1256,7 @@
shadowLayer.alpha = 1.0f;
ColorSourceVariant::fillColor(shadowLayer, 0, 0, 0, this);
shadowLayer.shadow = shadow;
- layers.push_back(&shadowLayer);
+ layers.push_back(shadowLayer);
invokeDraw(settings, layers);
}
@@ -1291,8 +1292,8 @@
// Transform the red color.
bgLayer.colorTransform = mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- std::vector<const renderengine::LayerSettings*> layers;
- layers.push_back(&bgLayer);
+ std::vector<renderengine::LayerSettings> layers;
+ layers.push_back(bgLayer);
invokeDraw(settings, layers);
@@ -1306,11 +1307,11 @@
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
- layers.push_back(&layer);
+ layers.push_back(layer);
std::future<renderengine::RenderEngineResult> result =
mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd());
@@ -1335,12 +1336,12 @@
settings.physicalDisplay = fullscreenRect();
settings.clip = fullscreenRect();
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0;
- layers.push_back(&layer);
+ layers.push_back(layer);
std::future<renderengine::RenderEngineResult> result =
mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd());
@@ -1743,12 +1744,12 @@
settings.clip = fullscreenRect();
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0;
- layers.push_back(&layer);
+ layers.push_back(layer);
std::future<renderengine::RenderEngineResult> resultOne =
mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
@@ -1779,7 +1780,7 @@
settings.clip = fullscreenRect();
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings redLayer;
redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1790,7 +1791,7 @@
redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
redLayer.alpha = 1.0f;
- layers.push_back(&redLayer);
+ layers.push_back(redLayer);
// Green layer with 1/3 size.
renderengine::LayerSettings greenLayer;
@@ -1805,7 +1806,7 @@
greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f);
greenLayer.alpha = 1.0f;
- layers.push_back(&greenLayer);
+ layers.push_back(greenLayer);
invokeDraw(settings, layers);
@@ -1828,7 +1829,7 @@
settings.clip = fullscreenRect();
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings redLayer;
redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1839,7 +1840,7 @@
redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
redLayer.alpha = 1.0f;
- layers.push_back(&redLayer);
+ layers.push_back(redLayer);
// Green layer with 1/2 size with parent crop rect.
renderengine::LayerSettings greenLayer = redLayer;
@@ -1847,7 +1848,7 @@
FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2);
greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f);
- layers.push_back(&greenLayer);
+ layers.push_back(greenLayer);
invokeDraw(settings, layers);
@@ -1873,7 +1874,7 @@
settings.clip = fullscreenRect();
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
renderengine::LayerSettings redLayer;
redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1884,7 +1885,7 @@
redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
redLayer.alpha = 1.0f;
- layers.push_back(&redLayer);
+ layers.push_back(redLayer);
invokeDraw(settings, layers);
// Due to roundedCornersRadius, the top corners are untouched.
@@ -1923,7 +1924,7 @@
.disableBlending = true,
};
- std::vector<const renderengine::LayerSettings*> layers{&redLayer, &clearLayer};
+ std::vector<renderengine::LayerSettings> layers{redLayer, clearLayer};
invokeDraw(display, layers);
expectBufferColor(rect, 0, 0, 0, 0);
}
@@ -1971,7 +1972,7 @@
.disableBlending = true,
};
- std::vector<const renderengine::LayerSettings*> layers{&redLayer, &greenLayer};
+ std::vector<renderengine::LayerSettings> layers{redLayer, greenLayer};
invokeDraw(display, layers);
expectBufferColor(rect, 0, 128, 0, 128);
}
@@ -2017,7 +2018,7 @@
.alpha = 1.0f,
};
- std::vector<const renderengine::LayerSettings*> layers{&greenLayer};
+ std::vector<renderengine::LayerSettings> layers{greenLayer};
invokeDraw(display, layers);
if (GetParam()->useColorManagement()) {
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 99250c1..db7e12b 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -172,20 +172,21 @@
TEST_F(RenderEngineThreadedTest, drawLayers) {
renderengine::DisplaySettings settings;
- std::vector<const renderengine::LayerSettings*> layers;
+ std::vector<renderengine::LayerSettings> layers;
std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine,
renderengine::ExternalTexture::Usage::READABLE |
renderengine::ExternalTexture::Usage::WRITEABLE);
+
base::unique_fd bufferFence;
EXPECT_CALL(*mRenderEngine, drawLayersInternal)
.WillOnce([&](const std::shared_ptr<std::promise<renderengine::RenderEngineResult>>&&
resultPromise,
const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>&,
+ const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> void {
+ base::unique_fd&&) -> void {
resultPromise->set_value({NO_ERROR, base::unique_fd()});
});
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index a549672..3d446e8 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -306,7 +306,7 @@
void RenderEngineThreaded::drawLayersInternal(
const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
- const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence) {
resultPromise->set_value({NO_ERROR, base::unique_fd()});
@@ -314,19 +314,20 @@
}
std::future<RenderEngineResult> RenderEngineThreaded::drawLayers(
- const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence) {
ATRACE_CALL();
const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
std::future<RenderEngineResult> resultFuture = resultPromise->get_future();
+ int fd = bufferFence.release();
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([resultPromise, &display, &layers, &buffer, useFramebufferCache,
- &bufferFence](renderengine::RenderEngine& instance) {
+ mFunctionCalls.push([resultPromise, display, layers, buffer, useFramebufferCache,
+ fd](renderengine::RenderEngine& instance) {
ATRACE_NAME("REThreaded::drawLayers");
instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer,
- useFramebufferCache, std::move(bufferFence));
+ useFramebufferCache, base::unique_fd(fd));
});
}
mCondition.notify_one();
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 2303caa..0159cfa 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -57,7 +57,7 @@
void cleanupPostRender() override;
std::future<RenderEngineResult> drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
+ const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer,
const bool useFramebufferCache,
base::unique_fd&& bufferFence) override;
@@ -73,7 +73,7 @@
bool canSkipPostRenderCleanup() const override;
void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
+ const std::vector<LayerSettings>& layers,
const std::shared_ptr<ExternalTexture>& buffer,
const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 80f6c82..8ac08fb 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -634,6 +634,12 @@
outSmpte2094_40);
}
+status_t Gralloc4Mapper::getSmpte2094_10(
+ buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_10) const {
+ return get(bufferHandle, gralloc4::MetadataType_Smpte2094_10, gralloc4::decodeSmpte2094_10,
+ outSmpte2094_10);
+}
+
template <class T>
status_t Gralloc4Mapper::getDefault(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index d20bd7a..82d6cd5 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -301,6 +301,11 @@
return mMapper->getSmpte2094_40(bufferHandle, outSmpte2094_40);
}
+status_t GraphicBufferMapper::getSmpte2094_10(
+ buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_10) {
+ return mMapper->getSmpte2094_10(bufferHandle, outSmpte2094_10);
+}
+
status_t GraphicBufferMapper::getDefaultPixelFormatFourCC(uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount,
uint64_t usage,
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index e199648..753b0a6 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -178,6 +178,11 @@
std::optional<std::vector<uint8_t>>* /*outSmpte2094_40*/) const {
return INVALID_OPERATION;
}
+ virtual status_t getSmpte2094_10(
+ buffer_handle_t /*bufferHandle*/,
+ std::optional<std::vector<uint8_t>>* /*outSmpte2094_10*/) const {
+ return INVALID_OPERATION;
+ }
virtual status_t getDefaultPixelFormatFourCC(uint32_t /*width*/, uint32_t /*height*/,
PixelFormat /*format*/, uint32_t /*layerCount*/,
diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h
index 4729cba..62f9e4a 100644
--- a/libs/ui/include/ui/Gralloc4.h
+++ b/libs/ui/include/ui/Gralloc4.h
@@ -108,6 +108,8 @@
std::optional<ui::Cta861_3>* outCta861_3) const override;
status_t getSmpte2094_40(buffer_handle_t bufferHandle,
std::optional<std::vector<uint8_t>>* outSmpte2094_40) const override;
+ status_t getSmpte2094_10(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>>* outSmpte2094_10) const override;
status_t getDefaultPixelFormatFourCC(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 837e3d8..257c155 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -126,6 +126,8 @@
status_t getCta861_3(buffer_handle_t bufferHandle, std::optional<ui::Cta861_3>* outCta861_3);
status_t getSmpte2094_40(buffer_handle_t bufferHandle,
std::optional<std::vector<uint8_t>>* outSmpte2094_40);
+ status_t getSmpte2094_10(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>>* outSmpte2094_10);
/**
* Gets the default metadata for a gralloc buffer allocated with the given parameters.
diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS
index 0997e9f..d073e2b 100644
--- a/libs/vibrator/OWNERS
+++ b/libs/vibrator/OWNERS
@@ -1,2 +1 @@
-lsandrade@google.com
-michaelwr@google.com
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
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 3db3907..176cf89 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -88,6 +88,9 @@
// Log debug messages about input focus tracking.
constexpr bool DEBUG_FOCUS = false;
+// Log debug messages about touch mode event
+constexpr bool DEBUG_TOUCH_MODE = false;
+
// Log debug messages about touch occlusion
// STOPSHIP(b/169067926): Set to false
constexpr bool DEBUG_TOUCH_OCCLUSION = true;
@@ -113,7 +116,7 @@
// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
bool isPerWindowInputRotationEnabled() {
static const bool PER_WINDOW_INPUT_ROTATION =
- sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);
+ sysprop::InputFlingerProperties::per_window_input_rotation().value_or(true);
return PER_WINDOW_INPUT_ROTATION;
}
@@ -150,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);
@@ -534,6 +538,23 @@
return transformedXy - transformedOrigin;
}
+// Returns true if the event type passed as argument represents a user activity.
+bool isUserActivityEvent(const EventEntry& eventEntry) {
+ switch (eventEntry.type) {
+ case EventEntry::Type::FOCUS:
+ case EventEntry::Type::POINTER_CAPTURE_CHANGED:
+ case EventEntry::Type::DRAG:
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
+ case EventEntry::Type::SENSOR:
+ case EventEntry::Type::CONFIGURATION_CHANGED:
+ return false;
+ case EventEntry::Type::DEVICE_RESET:
+ case EventEntry::Type::KEY:
+ case EventEntry::Type::MOTION:
+ return true;
+ }
+}
+
} // namespace
// --- InputDispatcher ---
@@ -552,7 +573,7 @@
// mInTouchMode will be initialized by the WindowManager to the default device config.
// To avoid leaking stack in case that call never comes, and for tests,
// initialize it here anyways.
- mInTouchMode(true),
+ mInTouchMode(kDefaultInTouchMode),
mMaximumObscuringOpacityForTouch(1.0f),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
@@ -1789,9 +1810,9 @@
displayId = motionEntry.displayId;
break;
}
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::FOCUS:
- case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::SENSOR:
@@ -2057,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();
}
@@ -2757,11 +2780,8 @@
}
void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) {
- if (eventEntry.type == EventEntry::Type::FOCUS ||
- eventEntry.type == EventEntry::Type::POINTER_CAPTURE_CHANGED ||
- eventEntry.type == EventEntry::Type::DRAG) {
- // Focus or pointer capture changed events are passed to apps, but do not represent user
- // activity.
+ if (!isUserActivityEvent(eventEntry)) {
+ // Not poking user activity if the event type does not represent a user activity
return;
}
int32_t displayId = getTargetDisplayId(eventEntry);
@@ -2797,16 +2817,7 @@
eventType = USER_ACTIVITY_EVENT_BUTTON;
break;
}
- case EventEntry::Type::TOUCH_MODE_CHANGED: {
- break;
- }
-
- case EventEntry::Type::FOCUS:
- case EventEntry::Type::CONFIGURATION_CHANGED:
- case EventEntry::Type::DEVICE_RESET:
- case EventEntry::Type::SENSOR:
- case EventEntry::Type::POINTER_CAPTURE_CHANGED:
- case EventEntry::Type::DRAG: {
+ default: {
LOG_ALWAYS_FATAL("%s events are not user activity",
ftl::enum_string(eventEntry.type).c_str());
break;
@@ -2862,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());
@@ -3567,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());
@@ -3781,7 +3801,7 @@
ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -3876,7 +3896,7 @@
std::to_string(t.duration().count()).c_str());
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
mLock.lock();
@@ -3953,7 +3973,7 @@
std::to_string(t.duration().count()).c_str());
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
mLock.lock();
@@ -4018,7 +4038,7 @@
ftl::enum_string(args->sensorType).c_str());
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
mLock.lock();
@@ -4068,7 +4088,7 @@
args->deviceId);
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -4088,7 +4108,7 @@
args->request.enable ? "true" : "false");
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
std::scoped_lock _l(mLock);
auto entry = std::make_unique<PointerCaptureChangedEntry>(args->id, args->eventTime,
@@ -4909,9 +4929,29 @@
}
void InputDispatcher::setInTouchMode(bool inTouchMode) {
- std::scoped_lock lock(mLock);
- mInTouchMode = inTouchMode;
- // TODO(b/193718270): Fire TouchModeEvent here.
+ bool needWake = false;
+ {
+ std::scoped_lock lock(mLock);
+ if (mInTouchMode == inTouchMode) {
+ return;
+ }
+ if (DEBUG_TOUCH_MODE) {
+ ALOGD("Request to change touch mode from %s to %s", toString(mInTouchMode),
+ toString(inTouchMode));
+ // TODO(b/198487159): Also print the current last interacted apps.
+ }
+
+ // TODO(b/198499018): Store touch mode per display.
+ mInTouchMode = inTouchMode;
+
+ // TODO(b/198487159): Enforce that only last interacted apps can change touch mode.
+ auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode);
+ needWake = enqueueInboundEventLocked(std::move(entry));
+ } // release lock
+
+ if (needWake) {
+ mLooper->wake();
+ }
}
void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 55ca6c9..8a551cf 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -82,6 +82,8 @@
*/
class InputDispatcher : public android::InputDispatcherInterface {
public:
+ static constexpr bool kDefaultInTouchMode = true;
+
explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
~InputDispatcher() override;
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 96c4378..197be98 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -33,7 +33,7 @@
// projection are part of the input window's transform. This means InputReader should work in the
// un-rotated coordinate space.
static bool isPerWindowInputRotationEnabled() {
- return sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);
+ return sysprop::InputFlingerProperties::per_window_input_rotation().value_or(true);
}
static int32_t getInverseRotation(int32_t orientation) {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 84e4276..ba0ce95 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -817,6 +817,9 @@
case AINPUT_EVENT_TYPE_CAPTURE: {
FAIL() << "Use 'consumeCaptureEvent' for CAPTURE events";
}
+ case AINPUT_EVENT_TYPE_TOUCH_MODE: {
+ FAIL() << "Use 'consumeTouchModeEvent' for TOUCH_MODE events";
+ }
case AINPUT_EVENT_TYPE_DRAG: {
FAIL() << "Use 'consumeDragEvent' for DRAG events";
}
@@ -874,6 +877,20 @@
EXPECT_EQ(y, dragEvent.getY());
}
+ void consumeTouchModeEvent(bool inTouchMode) {
+ const InputEvent* event = consume();
+ ASSERT_NE(nullptr, event) << mName.c_str()
+ << ": consumer should have returned non-NULL event.";
+ ASSERT_EQ(AINPUT_EVENT_TYPE_TOUCH_MODE, event->getType())
+ << "Got " << inputEventTypeToString(event->getType())
+ << " event instead of TOUCH_MODE event";
+
+ ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
+ << mName.c_str() << ": event displayId should always be NONE.";
+ const auto& touchModeEvent = static_cast<const TouchModeEvent&>(*event);
+ EXPECT_EQ(inTouchMode, touchModeEvent.isInTouchMode());
+ }
+
void assertNoEvents() {
InputEvent* event = consume();
if (event == nullptr) {
@@ -895,6 +912,10 @@
const auto& captureEvent = static_cast<CaptureEvent&>(*event);
ADD_FAILURE() << "Received capture event, pointerCaptureEnabled = "
<< (captureEvent.getPointerCaptureEnabled() ? "true" : "false");
+ } else if (event->getType() == AINPUT_EVENT_TYPE_TOUCH_MODE) {
+ const auto& touchModeEvent = static_cast<TouchModeEvent&>(*event);
+ ADD_FAILURE() << "Received touch mode event, inTouchMode = "
+ << (touchModeEvent.isInTouchMode() ? "true" : "false");
}
FAIL() << mName.c_str()
<< ": should not have received any events, so consume() should return NULL";
@@ -1091,6 +1112,12 @@
mInputReceiver->consumeDragEvent(isExiting, x, y);
}
+ void consumeTouchModeEvent(bool inTouchMode) {
+ ASSERT_NE(mInputReceiver, nullptr)
+ << "Cannot consume events from a window with no receiver";
+ mInputReceiver->consumeTouchModeEvent(inTouchMode);
+ }
+
std::optional<uint32_t> receiveEvent(InputEvent** outEvent = nullptr) {
if (mInputReceiver == nullptr) {
ADD_FAILURE() << "Invalid receive event on window with no receiver";
@@ -2814,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 =
@@ -2857,7 +2895,6 @@
SCOPED_TRACE("Check default value of touch mode");
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
-
window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
SCOPED_TRACE("Remove the window to trigger focus loss");
@@ -2867,6 +2904,7 @@
SCOPED_TRACE("Disable touch mode");
mDispatcher->setInTouchMode(false);
+ window->consumeTouchModeEvent(false);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
@@ -2879,6 +2917,7 @@
SCOPED_TRACE("Enable touch mode again");
mDispatcher->setInTouchMode(true);
+ window->consumeTouchModeEvent(true);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
@@ -6024,4 +6063,43 @@
window->assertNoEvents();
}
+class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
+protected:
+ std::shared_ptr<FakeApplicationHandle> mApp;
+ sp<FakeWindowHandle> mWindow;
+ sp<FakeWindowHandle> mSecondWindow;
+
+ void SetUp() override {
+ InputDispatcherTest::SetUp();
+
+ mApp = std::make_shared<FakeApplicationHandle>();
+ mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mWindow->setFocusable(true);
+ mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+ mSecondWindow->setFocusable(true);
+
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
+
+ setFocusedWindow(mWindow);
+ mWindow->consumeFocusEvent(true);
+ }
+
+ void changeAndVerifyTouchMode(bool inTouchMode) {
+ mDispatcher->setInTouchMode(inTouchMode);
+ mWindow->consumeTouchModeEvent(inTouchMode);
+ mSecondWindow->consumeTouchModeEvent(inTouchMode);
+ }
+};
+
+TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchModeOnFocusedWindow) {
+ changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode);
+}
+
+TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
+ mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode);
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index bba6e22..1be5a96 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -77,7 +77,6 @@
"libsensor",
"libsensorprivacy",
"libpermission",
- "packagemanager_aidl-cpp",
],
}
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index c285c00..46f00e8 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -92,31 +92,13 @@
}
status_t ProximitySensor::activate(void* ident, bool enabled) {
- bool lastState = mSensorDevice.isSensorActive(mSensor.getHandle());
-
status_t status = HardwareSensor::activate(ident, enabled);
if (status != NO_ERROR) {
return status;
}
-
- bool currentState = mSensorDevice.isSensorActive(mSensor.getHandle());
- if (currentState != lastState) {
- mSensorService.onProximityActiveLocked(currentState);
- }
+ mSensorService.checkAndReportProxStateChangeLocked();
return NO_ERROR;
}
-void ProximitySensor::willDisableAllSensors() {
- if (mSensorDevice.isSensorActive(mSensor.getHandle())) {
- mSensorService.onProximityActiveLocked(false);
- }
-}
-
-void ProximitySensor::didEnableAllSensors() {
- if (mSensorDevice.isSensorActive(mSensor.getHandle())) {
- mSensorService.onProximityActiveLocked(true);
- }
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index 4e9f7bf..5704359 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -44,9 +44,6 @@
virtual const Sensor& getSensor() const = 0;
virtual bool isVirtual() const = 0;
virtual void autoDisable(void* /*ident*/, int /*handle*/) = 0;
-
- virtual void willDisableAllSensors() = 0;
- virtual void didEnableAllSensors() = 0;
};
class BaseSensor : public SensorInterface {
@@ -70,8 +67,6 @@
virtual const Sensor& getSensor() const override { return mSensor; }
virtual void autoDisable(void* /*ident*/, int /*handle*/) override { }
- virtual void willDisableAllSensors() override { }
- virtual void didEnableAllSensors() override { }
protected:
SensorDevice& mSensorDevice;
Sensor mSensor;
@@ -115,8 +110,6 @@
status_t activate(void* ident, bool enabled) override;
- void willDisableAllSensors() override;
- void didEnableAllSensors() override;
private:
SensorService& mSensorService;
};
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8c3a24f..32a0110 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -103,7 +103,7 @@
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
- mWakeLockAcquired(false), mProximityActiveCount(0) {
+ mWakeLockAcquired(false), mLastReportedProxIsActive(false) {
mUidPolicy = new UidPolicy(this);
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
}
@@ -204,9 +204,11 @@
}
if (useThisSensor) {
if (list[i].type == SENSOR_TYPE_PROXIMITY) {
- registerSensor(new ProximitySensor(list[i], *this));
+ SensorInterface* s = new ProximitySensor(list[i], *this);
+ registerSensor(s);
+ mProxSensorHandles.push_back(s->getSensor().getHandle());
} else {
- registerSensor( new HardwareSensor(list[i]) );
+ registerSensor(new HardwareSensor(list[i]));
}
}
}
@@ -331,6 +333,7 @@
conn->onSensorAccessChanged(hasAccess);
}
}
+ checkAndReportProxStateChangeLocked();
}
bool SensorService::hasSensorAccess(uid_t uid, const String16& opPackageName) {
@@ -680,11 +683,8 @@
bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
conn->onSensorAccessChanged(hasAccess);
}
- mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
- e.si->willDisableAllSensors();
- return true;
- });
dev.disableAllSensors();
+ checkAndReportProxStateChangeLocked();
// Clear all pending flush connections for all active sensors. If one of the active
// connections has called flush() and the underlying sensor has been disabled before a
// flush complete event is returned, we need to remove the connection from this queue.
@@ -709,14 +709,11 @@
}
SensorDevice& dev(SensorDevice::getInstance());
dev.enableAllSensors();
- mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
- e.si->didEnableAllSensors();
- return true;
- });
for (const sp<SensorDirectConnection>& conn : connLock->getDirectConnections()) {
bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
conn->onSensorAccessChanged(hasAccess);
}
+ checkAndReportProxStateChangeLocked();
}
void SensorService::capRates(userid_t userId) {
@@ -1538,10 +1535,7 @@
if (err == NO_ERROR) {
mCurrentOperatingMode = NORMAL;
dev.enableAllSensors();
- mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
- e.si->didEnableAllSensors();
- return true;
- });
+ checkAndReportProxStateChangeLocked();
}
return err;
}
@@ -1606,28 +1600,26 @@
mConnectionHolder.removeDirectConnection(c);
}
-void SensorService::onProximityActiveLocked(bool isActive) {
- int prevCount = mProximityActiveCount;
- bool activeStateChanged = false;
- if (isActive) {
- mProximityActiveCount++;
- activeStateChanged = prevCount == 0;
- } else {
- mProximityActiveCount--;
- if (mProximityActiveCount < 0) {
- ALOGE("Proximity active count is negative (%d)!", mProximityActiveCount);
- }
- activeStateChanged = prevCount > 0 && mProximityActiveCount <= 0;
- }
+void SensorService::checkAndReportProxStateChangeLocked() {
+ if (mProxSensorHandles.empty()) return;
- if (activeStateChanged) {
- notifyProximityStateLocked(mProximityActiveListeners);
+ SensorDevice& dev(SensorDevice::getInstance());
+ bool isActive = false;
+ for (auto& sensor : mProxSensorHandles) {
+ if (dev.isSensorActive(sensor)) {
+ isActive = true;
+ break;
+ }
+ }
+ if (isActive != mLastReportedProxIsActive) {
+ notifyProximityStateLocked(isActive, mProximityActiveListeners);
+ mLastReportedProxIsActive = isActive;
}
}
void SensorService::notifyProximityStateLocked(
+ const bool isActive,
const std::vector<sp<ProximityActiveListener>>& listeners) {
- const bool isActive = mProximityActiveCount > 0;
const uint64_t mySeq = ++curProxCallbackSeq;
std::thread t([isActive, mySeq, listenersCopy = listeners]() {
while (completedCallbackSeq.load() != mySeq - 1)
@@ -1655,7 +1647,7 @@
mProximityActiveListeners.push_back(callback);
std::vector<sp<ProximityActiveListener>> listener(1, callback);
- notifyProximityStateLocked(listener);
+ notifyProximityStateLocked(mLastReportedProxIsActive, listener);
return OK;
}
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index def6611..b059e61 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -103,8 +103,9 @@
void cleanupConnection(SensorDirectConnection* c);
// Call with mLock held.
- void onProximityActiveLocked(bool isActive);
- void notifyProximityStateLocked(const std::vector<sp<ProximityActiveListener>>& listeners);
+ void checkAndReportProxStateChangeLocked();
+ void notifyProximityStateLocked(const bool isActive,
+ const std::vector<sp<ProximityActiveListener>>& listeners);
status_t enable(const sp<SensorEventConnection>& connection, int handle,
nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
@@ -496,8 +497,11 @@
// Checks if the mic sensor privacy is enabled for the uid
bool isMicSensorPrivacyEnabledForUid(uid_t uid);
- // Counts how many proximity sensors are currently active.
- int mProximityActiveCount;
+ // Keeps track of the handles of all proximity sensors in the system.
+ std::vector<int32_t> mProxSensorHandles;
+ // The last proximity sensor active state reported to listeners.
+ bool mLastReportedProxIsActive;
+ // Listeners subscribed to receive updates on the proximity sensor active state.
std::vector<sp<ProximityActiveListener>> mProximityActiveListeners;
};
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index af012cd..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",
@@ -102,7 +110,7 @@
// TODO (marissaw): this library is not used by surfaceflinger. This is here so
// the library compiled in a way that is accessible to system partition when running
// IMapper's VTS.
- required: ["libgralloctypes"]
+ required: ["libgralloctypes"],
}
cc_defaults {
@@ -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",
@@ -191,6 +201,7 @@
"SurfaceFlingerDefaultFactory.cpp",
"SurfaceInterceptor.cpp",
"SurfaceTracing.cpp",
+ "Tracing/TransactionProtoParser.cpp",
"TransactionCallbackInvoker.cpp",
"TunnelModeEnabledReporter.cpp",
],
@@ -249,7 +260,7 @@
"libSurfaceFlingerProp",
],
- logtags: ["EventLog/EventLogTags.logtags"],
+ logtags: ["EventLog/EventLogTags.logtags"],
}
subdirs = [
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ef05fe2..861d496 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -111,6 +111,10 @@
return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat());
}
+bool BufferLayer::canReceiveInput() const {
+ return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f);
+}
+
bool BufferLayer::isVisible() const {
return !isHiddenByPolicy() && getAlpha() > 0.0f &&
(mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr);
@@ -346,13 +350,13 @@
}
} // namespace
-bool BufferLayer::onPostComposition(const DisplayDevice* display,
+void BufferLayer::onPostComposition(const DisplayDevice* display,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) {
// mFrameLatencyNeeded is true when a new frame was latched for the
// composition.
- if (!mBufferInfo.mFrameLatencyNeeded) return false;
+ if (!mBufferInfo.mFrameLatencyNeeded) return;
// Update mFrameEventHistory.
{
@@ -426,7 +430,6 @@
mFrameTracker.advanceFrame();
mBufferInfo.mFrameLatencyNeeded = false;
- return true;
}
void BufferLayer::gatherBufferInfo() {
@@ -486,7 +489,7 @@
// try again later
if (!fenceHasSignaled()) {
ATRACE_NAME("!fenceHasSignaled()");
- mFlinger->signalLayerUpdate();
+ mFlinger->onLayerUpdate();
return false;
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 2da73f8..8c4c8b7 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -62,6 +62,7 @@
void useEmptyDamage() override;
bool isOpaque(const Layer::State& s) const override;
+ bool canReceiveInput() const override;
// isVisible - true if this layer is visible, false otherwise
bool isVisible() const override;
@@ -77,7 +78,7 @@
bool isHdrY410() const override;
- bool onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
+ void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming&) override;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 96b2247..c79fa11 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -438,7 +438,7 @@
}
void BufferLayerConsumer::onSidebandStreamChanged() {
- FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
+ [[maybe_unused]] FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
{
Mutex::Autolock lock(mFrameAvailableMutex);
unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 8bbe438..4e5d2d0 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -48,7 +48,9 @@
// Interface implementation for Layer
// -----------------------------------------------------------------------
-void BufferQueueLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+void BufferQueueLayer::onLayerDisplayed(
+ std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
+ sp<Fence> releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence));
mConsumer->setReleaseFence(releaseFence);
// Prevent tracing the same release multiple times.
@@ -65,16 +67,6 @@
mConsumer->setTransformHint(mTransformHint);
}
-std::vector<OccupancyTracker::Segment> BufferQueueLayer::getOccupancyHistory(bool forceFlush) {
- std::vector<OccupancyTracker::Segment> history;
- status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
- if (result != NO_ERROR) {
- ALOGW("[%s] Failed to obtain occupancy history (%d)", getDebugName(), result);
- return {};
- }
- return history;
-}
-
void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
if (!mConsumer->releasePendingBuffer()) {
return;
@@ -228,7 +220,7 @@
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
- mFlinger->signalLayerUpdate();
+ mFlinger->onLayerUpdate();
return BAD_VALUE;
} else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
// If the buffer has been rejected, remove it from the shadow queue
@@ -309,7 +301,7 @@
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if ((queuedBuffer && more_frames_pending) || mAutoRefresh) {
- mFlinger->signalLayerUpdate();
+ mFlinger->onLayerUpdate();
}
return NO_ERROR;
@@ -412,7 +404,7 @@
mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(), item.mFrameNumber);
- mFlinger->signalLayerUpdate();
+ mFlinger->onLayerUpdate();
mConsumer->onBufferAvailable(item);
}
@@ -458,7 +450,7 @@
bool sidebandStreamChanged = false;
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, true)) {
// mSidebandStreamChanged was changed to true
- mFlinger->signalLayerUpdate();
+ mFlinger->onLayerUpdate();
}
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index be2902b..dfdb5c0 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -42,9 +42,8 @@
// Implements Layer.
const char* getType() const override { return "BufferQueueLayer"; }
- void onLayerDisplayed(const sp<Fence>& releaseFence) override;
-
- std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
+ void onLayerDisplayed(
+ std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
// If a buffer was replaced this frame, release the former buffer
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4eeaba1..c0753f9 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -40,13 +40,13 @@
namespace {
void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, uint64_t framenumber,
- const sp<Fence>& releaseFence, uint32_t transformHint,
+ const sp<Fence>& releaseFence,
uint32_t currentMaxAcquiredBufferCount) {
if (!listener) {
return;
}
listener->onReleaseBuffer({buffer->getId(), framenumber},
- releaseFence ? releaseFence : Fence::NO_FENCE, transformHint,
+ releaseFence ? releaseFence : Fence::NO_FENCE,
currentMaxAcquiredBufferCount);
}
} // namespace
@@ -64,75 +64,17 @@
if (mBufferInfo.mBuffer != nullptr && !isClone()) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
- mBufferInfo.mFence, mTransformHint,
+ mBufferInfo.mFence,
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
mOwnerUid));
}
}
-status_t BufferStateLayer::addReleaseFence(const sp<CallbackHandle>& ch,
- const sp<Fence>& fence) {
- if (ch == nullptr) {
- return OK;
- }
- ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
- if (!ch->previousReleaseFence.get()) {
- ch->previousReleaseFence = fence;
- return OK;
- }
-
- // Below logic is lifted from ConsumerBase.cpp:
- // Check status of fences first because merging is expensive.
- // Merging an invalid fence with any other fence results in an
- // invalid fence.
- auto currentStatus = ch->previousReleaseFence->getStatus();
- if (currentStatus == Fence::Status::Invalid) {
- ALOGE("Existing fence has invalid state, layer: %s", mName.c_str());
- return BAD_VALUE;
- }
-
- auto incomingStatus = fence->getStatus();
- if (incomingStatus == Fence::Status::Invalid) {
- ALOGE("New fence has invalid state, layer: %s", mName.c_str());
- ch->previousReleaseFence = fence;
- return BAD_VALUE;
- }
-
- // If both fences are signaled or both are unsignaled, we need to merge
- // them to get an accurate timestamp.
- if (currentStatus == incomingStatus) {
- char fenceName[32] = {};
- snprintf(fenceName, 32, "%.28s", mName.c_str());
- sp<Fence> mergedFence = Fence::merge(
- fenceName, ch->previousReleaseFence, fence);
- if (!mergedFence.get()) {
- ALOGE("failed to merge release fences, layer: %s", mName.c_str());
- // synchronization is broken, the best we can do is hope fences
- // signal in order so the new fence will act like a union
- ch->previousReleaseFence = fence;
- return BAD_VALUE;
- }
- ch->previousReleaseFence = mergedFence;
- } else if (incomingStatus == Fence::Status::Unsignaled) {
- // If one fence has signaled and the other hasn't, the unsignaled
- // fence will approximately correspond with the correct timestamp.
- // There's a small race if both fences signal at about the same time
- // and their statuses are retrieved with unfortunate timing. However,
- // by this point, they will have both signaled and only the timestamp
- // will be slightly off; any dependencies after this point will
- // already have been met.
- ch->previousReleaseFence = fence;
- }
- // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
-
- return OK;
-}
-
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
-
+void BufferStateLayer::onLayerDisplayed(
+ std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
// If a layer has been displayed again we may need to clear
// the mLastClientComposition fence that we use for early release in setBuffer
// (as we now have a new fence which won't pass through the client composition path in some cases
@@ -146,9 +88,6 @@
mLastClientCompositionDisplayed = true;
}
- if (!releaseFence->isValid()) {
- return;
- }
// The previous release fence notifies the client that SurfaceFlinger is done with the previous
// buffer that was presented on this layer. The first transaction that came in this frame that
// replaced the previous buffer on this layer needs this release fence, because the fence will
@@ -173,17 +112,17 @@
break;
}
}
- auto status = addReleaseFence(ch, releaseFence);
- if (status != OK) {
- ALOGE("Failed to add release fence for layer %s", getName().c_str());
- }
-
- mPreviousReleaseFence = releaseFence;
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
mPreviousReleasedFrameNumber = mPreviousFrameNumber;
}
+
+ if (ch != nullptr) {
+ ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
+ ch->previousReleaseFences.emplace_back(futureRenderEngineResult);
+ ch->name = mName;
+ }
}
void BufferStateLayer::onSurfaceFrameCreated(
@@ -231,9 +170,18 @@
mFlinger->getTransactionCallbackInvoker().addCallbackHandles(
mDrawingState.callbackHandles, jankData);
+ sp<Fence> releaseFence = Fence::NO_FENCE;
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
+ releaseFence =
+ handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE;
+ break;
+ }
+ }
+
mDrawingState.callbackHandles = {};
- const sp<Fence>& releaseFence(mPreviousReleaseFence);
std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(releaseFence);
{
Mutex::Autolock lock(mFrameEventHistoryMutex);
@@ -479,7 +427,7 @@
// call any release buffer callbacks if set.
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mDrawingState.acquireFence, mTransformHint,
+ mDrawingState.acquireFence,
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
mOwnerUid));
decrementPendingBufferCount();
@@ -491,9 +439,9 @@
} else if (mLastClientCompositionFence != nullptr) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mLastClientCompositionFence, mTransformHint,
+ mLastClientCompositionFence,
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
- mOwnerUid));
+ mOwnerUid));
mLastClientCompositionFence = nullptr;
}
}
@@ -595,7 +543,7 @@
setTransactionFlags(eTransactionNeeded);
if (!mSidebandStreamChanged.exchange(true)) {
// mSidebandStreamChanged was false
- mFlinger->signalLayerUpdate();
+ mFlinger->onLayerUpdate();
}
return true;
}
@@ -713,7 +661,7 @@
void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
if (!mAutoRefresh.exchange(autoRefresh)) {
- mFlinger->signalLayerUpdate();
+ mFlinger->onLayerUpdate();
}
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 87b68ea..eea700c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -39,7 +39,9 @@
// Implements Layer.
const char* getType() const override { return "BufferStateLayer"; }
- void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+ void onLayerDisplayed(
+ std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
+
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
@@ -115,8 +117,6 @@
bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
nsecs_t requestedPresentTime);
- status_t addReleaseFence(const sp<CallbackHandle>& ch, const sp<Fence>& releaseFence);
-
bool latchSidebandStream(bool& recomputeVisibleRegions) override;
bool hasFrameUpdate() const override;
@@ -139,7 +139,6 @@
std::shared_ptr<renderengine::ExternalTexture> getBufferFromBufferData(
const BufferData& bufferData);
- sp<Fence> mPreviousReleaseFence;
ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
uint64_t mPreviousReleasedFrameNumber = 0;
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/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index 95d553d..93586ed 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -85,8 +85,8 @@
// to prevent an early presentation of a frame.
std::shared_ptr<FenceTime> previousPresentFence;
- // The predicted next invalidation time
- std::optional<std::chrono::steady_clock::time_point> nextInvalidateTime;
+ // If set, a frame has been scheduled for that time.
+ std::optional<std::chrono::steady_clock::time_point> scheduledFrameTime;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index f7b71cf..ac243c0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,6 +16,7 @@
#pragma once
+#include <future>
#include <optional>
#include <ostream>
#include <unordered_set>
@@ -26,6 +27,7 @@
#pragma clang diagnostic ignored "-Wextra"
#include <renderengine/LayerSettings.h>
+#include <renderengine/RenderEngine.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
@@ -151,7 +153,7 @@
ClientCompositionTargetSettings&) = 0;
// Called after the layer is displayed to update the presentation fence
- virtual void onLayerDisplayed(const sp<Fence>&) = 0;
+ virtual void onLayerDisplayed(std::shared_future<renderengine::RenderEngineResult>) = 0;
// Gets some kind of identifier for the layer for debug purposes.
virtual const char* getDebugName() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index d215bda..16aebef 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -39,7 +39,7 @@
std::vector<compositionengine::LayerFE::LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
- MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
+ MOCK_METHOD1(onLayerDisplayed, void(std::shared_future<renderengine::RenderEngineResult>));
MOCK_CONST_METHOD0(getDebugName, const char*());
MOCK_CONST_METHOD0(getSequence, int32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 048d7c2..6800004 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -27,6 +27,7 @@
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
+#include <ftl/future.h>
#include <thread>
@@ -1097,12 +1098,12 @@
setExpensiveRenderingExpected(true);
}
- std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
- clientCompositionLayerPointers.reserve(clientCompositionLayers.size());
+ std::vector<renderengine::LayerSettings> clientRenderEngineLayers;
+ clientRenderEngineLayers.reserve(clientCompositionLayers.size());
std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
- std::back_inserter(clientCompositionLayerPointers),
- [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* {
- return &settings;
+ std::back_inserter(clientRenderEngineLayers),
+ [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings {
+ return settings;
});
const nsecs_t renderEngineStart = systemTime();
@@ -1115,7 +1116,7 @@
const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay;
auto [status, drawFence] =
renderEngine
- .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex,
+ .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex,
useFramebufferCache, std::move(fd))
.get();
@@ -1295,8 +1296,10 @@
releaseFence =
Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
}
-
- layer->getLayerFE().onLayerDisplayed(releaseFence);
+ layer->getLayerFE().onLayerDisplayed(
+ ftl::yield<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd(releaseFence->dup())})
+ .share());
}
// We've got a list of layers needing fences, that are disjoint with
@@ -1304,7 +1307,9 @@
// supply them with the present fence.
for (auto& weakLayer : mReleasedLayers) {
if (auto layer = weakLayer.promote(); layer != nullptr) {
- layer->onLayerDisplayed(frame.presentFence);
+ layer->onLayerDisplayed(ftl::yield<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd(frame.presentFence->dup())})
+ .share());
}
}
@@ -1314,7 +1319,7 @@
void Output::renderCachedSets(const CompositionRefreshArgs& refreshArgs) {
if (mPlanner) {
- mPlanner->renderCachedSets(getState(), refreshArgs.nextInvalidateTime);
+ mPlanner->renderCachedSets(getState(), refreshArgs.scheduledFrameTime);
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index ecfd901..e958549 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -381,12 +381,7 @@
if (outputDependentState.overrideInfo.buffer != nullptr) {
displayFrame = outputDependentState.overrideInfo.displayFrame;
- sourceCrop =
- FloatRect(0.f, 0.f,
- static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
- ->getWidth()),
- static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
- ->getHeight()));
+ sourceCrop = displayFrame.toFloatRect();
}
ALOGV("Writing display frame [%d, %d, %d, %d]", displayFrame.left, displayFrame.top,
@@ -737,7 +732,7 @@
// framebuffer space of the override buffer to layer space.
const ProjectionSpace& layerSpace = getOutput().getState().layerStackSpace;
const ui::Transform transform = getState().overrideInfo.displaySpace.getTransform(layerSpace);
- const Rect boundaries = transform.transform(getState().overrideInfo.displayFrame);
+ const Rect boundaries = transform.transform(getState().overrideInfo.displaySpace.getContent());
LayerFE::LayerSettings settings;
settings.geometry = renderengine::Geometry{
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index e6b716e..ec52e59 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -193,11 +193,6 @@
clientCompositionList.cend());
}
- std::vector<const renderengine::LayerSettings*> layerSettingsPointers;
- std::transform(layerSettings.cbegin(), layerSettings.cend(),
- std::back_inserter(layerSettingsPointers),
- [](const renderengine::LayerSettings& settings) { return &settings; });
-
renderengine::LayerSettings blurLayerSettings;
if (mBlurLayer) {
auto blurSettings = targetSettings;
@@ -212,7 +207,7 @@
blurLayerSettings.name = std::string("blur layer");
// Clear out the shadow settings
blurLayerSettings.shadow = {};
- layerSettingsPointers.push_back(&blurLayerSettings);
+ layerSettings.push_back(blurLayerSettings);
}
renderengine::LayerSettings holePunchSettings;
@@ -230,7 +225,7 @@
holePunchSettings.disableBlending = true;
holePunchSettings.alpha = 0.0f;
holePunchSettings.name = std::string("hole punch layer");
- layerSettingsPointers.push_back(&holePunchSettings);
+ layerSettings.push_back(holePunchSettings);
// Add a solid background as the first layer in case there is no opaque
// buffer behind the punch hole
@@ -239,7 +234,7 @@
holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries;
holePunchBackgroundSettings.geometry.positionTransform =
holePunchSettings.geometry.positionTransform;
- layerSettingsPointers.insert(layerSettingsPointers.begin(), &holePunchBackgroundSettings);
+ layerSettings.emplace(layerSettings.begin(), holePunchBackgroundSettings);
}
if (sDebugHighlighLayers) {
@@ -257,7 +252,7 @@
.alpha = half(0.05f),
};
- layerSettingsPointers.emplace_back(&highlight);
+ layerSettings.emplace_back(highlight);
}
auto texture = texturePool.borrowTexture();
@@ -273,8 +268,8 @@
}
auto [status, drawFence] = renderEngine
- .drawLayers(displaySettings, layerSettingsPointers,
- texture->get(), false, std::move(bufferFence))
+ .drawLayers(displaySettings, layerSettings, texture->get(),
+ false, std::move(bufferFence))
.get();
if (status == NO_ERROR) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index ad5e931..2272099 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -315,7 +315,7 @@
state.overrideInfo = {
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
- .displayFrame = mNewCachedSet->getTextureBounds(),
+ .displayFrame = mNewCachedSet->getBounds(),
.dataspace = mNewCachedSet->getOutputDataspace(),
.displaySpace = mNewCachedSet->getOutputSpace(),
.damageRegion = Region::INVALID_REGION,
@@ -355,7 +355,7 @@
state.overrideInfo = {
.buffer = currentLayerIter->getBuffer(),
.acquireFence = currentLayerIter->getDrawFence(),
- .displayFrame = currentLayerIter->getTextureBounds(),
+ .displayFrame = currentLayerIter->getBounds(),
.dataspace = currentLayerIter->getOutputDataspace(),
.displaySpace = currentLayerIter->getOutputSpace(),
.damageRegion = Region(),
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/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 53b71b7..fbc2089 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -876,7 +876,7 @@
84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044};
-const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{0.f, 0.f, 4.f, 5.f};
+const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{1002, 1003, 1004, 20044};
const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
Rect{1005, 1006, 1007, 1008}};
const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}};
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 8f0028c..cf63ef5 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -24,6 +24,7 @@
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
+#include <ftl/future.h>
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/Rect.h>
@@ -2884,12 +2885,24 @@
// are passed. This happens to work with the current implementation, but
// would not survive certain calls like Fence::merge() which would return a
// new instance.
- EXPECT_CALL(*mLayer1.layerFE,
- onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer1Fence.get()))));
- EXPECT_CALL(*mLayer2.layerFE,
- onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer2Fence.get()))));
- EXPECT_CALL(*mLayer3.layerFE,
- onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer3Fence.get()))));
+ base::unique_fd layer1FD(layer1Fence->dup());
+ base::unique_fd layer2FD(layer2Fence->dup());
+ base::unique_fd layer3FD(layer3Fence->dup());
+ EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_))
+ .WillOnce([&layer1FD](std::shared_future<renderengine::RenderEngineResult>
+ futureRenderEngineResult) {
+ EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence);
+ });
+ EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_))
+ .WillOnce([&layer2FD](std::shared_future<renderengine::RenderEngineResult>
+ futureRenderEngineResult) {
+ EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence);
+ });
+ EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_))
+ .WillOnce([&layer3FD](std::shared_future<renderengine::RenderEngineResult>
+ futureRenderEngineResult) {
+ EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence);
+ });
mOutput.postFramebuffer();
}
@@ -2915,9 +2928,9 @@
// Fence::merge is called, and since none of the fences are actually valid,
// Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call.
// This is the best we can do without creating a real kernel fence object.
- EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(Fence::NO_FENCE));
- EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(Fence::NO_FENCE));
- EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(Fence::NO_FENCE));
+ EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed).WillOnce(Return());
+ EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed).WillOnce(Return());
+ EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed).WillOnce(Return());
mOutput.postFramebuffer();
}
@@ -2949,12 +2962,22 @@
EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
// Each released layer should be given the presentFence.
- EXPECT_CALL(*releasedLayer1,
- onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
- EXPECT_CALL(*releasedLayer2,
- onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
- EXPECT_CALL(*releasedLayer3,
- onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
+ base::unique_fd layerFD(presentFence.get()->dup());
+ EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_))
+ .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+ futureRenderEngineResult) {
+ EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+ });
+ EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_))
+ .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+ futureRenderEngineResult) {
+ EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+ });
+ EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_))
+ .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+ futureRenderEngineResult) {
+ EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+ });
mOutput.postFramebuffer();
@@ -3131,9 +3154,9 @@
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _))
.WillRepeatedly([&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>&,
+ const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&)
+ base::unique_fd&&)
-> std::future<renderengine::RenderEngineResult> {
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
});
@@ -3161,11 +3184,11 @@
}));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
.WillRepeatedly([&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>&,
+ const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&)
+ base::unique_fd&&)
-> std::future<renderengine::RenderEngineResult> {
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
});
@@ -3196,11 +3219,11 @@
}));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, true, _))
.WillRepeatedly([&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>&,
+ const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&)
+ base::unique_fd&&)
-> std::future<renderengine::RenderEngineResult> {
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
});
@@ -3226,7 +3249,7 @@
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
.Times(2)
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))))
@@ -3258,7 +3281,7 @@
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -3294,11 +3317,11 @@
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
.WillOnce(Return(mOutputBuffer))
.WillOnce(Return(otherOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
.WillRepeatedly([&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>&,
+ const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&)
+ base::unique_fd&&)
-> std::future<renderengine::RenderEngineResult> {
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
});
@@ -3330,10 +3353,10 @@
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r3), _, false, _))
.WillOnce(Return(ByMove(
futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
@@ -3487,9 +3510,9 @@
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
.WillRepeatedly(
[&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>&,
+ const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
return futureOf<renderengine::RenderEngineResult>(
{NO_ERROR, base::unique_fd()});
});
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index ecb05f8..42b3d97 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -346,15 +346,15 @@
const auto drawLayers =
[&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::vector<renderengine::LayerSettings>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
displaySettings.orientation);
- EXPECT_EQ(0.5f, layers[0]->alpha);
- EXPECT_EQ(0.75f, layers[1]->alpha);
+ EXPECT_EQ(0.5f, layers[0].alpha);
+ EXPECT_EQ(0.75f, layers[1].alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
@@ -398,15 +398,15 @@
const auto drawLayers =
[&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::vector<renderengine::LayerSettings>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
displaySettings.orientation);
- EXPECT_EQ(0.5f, layers[0]->alpha);
- EXPECT_EQ(0.75f, layers[1]->alpha);
+ EXPECT_EQ(0.5f, layers[0].alpha);
+ EXPECT_EQ(0.75f, layers[1].alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -453,15 +453,15 @@
const auto drawLayers =
[&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::vector<renderengine::LayerSettings>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
displaySettings.orientation);
- EXPECT_EQ(0.5f, layers[0]->alpha);
- EXPECT_EQ(0.75f, layers[1]->alpha);
+ EXPECT_EQ(0.5f, layers[0].alpha);
+ EXPECT_EQ(0.75f, layers[1].alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -656,26 +656,26 @@
const auto drawLayers =
[&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::vector<renderengine::LayerSettings>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
// If the highlight layer is enabled, it will increase the size by 1.
// We're interested in the third layer either way.
EXPECT_GE(layers.size(), 4u);
{
- const auto* holePunchSettings = layers[3];
- EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
- EXPECT_TRUE(holePunchSettings->disableBlending);
- EXPECT_EQ(0.0f, holePunchSettings->alpha);
+ const auto holePunchSettings = layers[3];
+ EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor);
+ EXPECT_TRUE(holePunchSettings.disableBlending);
+ EXPECT_EQ(0.0f, holePunchSettings.alpha);
}
{
- const auto* holePunchBackgroundSettings = layers[0];
- EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer);
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor);
- EXPECT_FALSE(holePunchBackgroundSettings->disableBlending);
- EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
+ const auto holePunchBackgroundSettings = layers[0];
+ EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor);
+ EXPECT_FALSE(holePunchBackgroundSettings.disableBlending);
+ EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha);
}
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -717,27 +717,27 @@
const auto drawLayers =
[&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::vector<renderengine::LayerSettings>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
// If the highlight layer is enabled, it will increase the size by 1.
// We're interested in the third layer either way.
EXPECT_GE(layers.size(), 4u);
{
- const auto* holePunchSettings = layers[3];
- EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
- EXPECT_TRUE(holePunchSettings->disableBlending);
- EXPECT_EQ(0.0f, holePunchSettings->alpha);
+ const auto holePunchSettings = layers[3];
+ EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor);
+ EXPECT_TRUE(holePunchSettings.disableBlending);
+ EXPECT_EQ(0.0f, holePunchSettings.alpha);
}
{
- const auto* holePunchBackgroundSettings = layers[0];
- EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer);
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor);
- EXPECT_FALSE(holePunchBackgroundSettings->disableBlending);
- EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
+ const auto holePunchBackgroundSettings = layers[0];
+ EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor);
+ EXPECT_FALSE(holePunchBackgroundSettings.disableBlending);
+ EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha);
}
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -867,16 +867,16 @@
const auto drawLayers =
[&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::vector<renderengine::LayerSettings>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
// If the highlight layer is enabled, it will increase the size by 1.
// We're interested in the third layer either way.
EXPECT_GE(layers.size(), 3u);
- const auto* blurSettings = layers[2];
- EXPECT_TRUE(blurSettings->skipContentDraw);
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings->source.solidColor);
- EXPECT_EQ(0.0f, blurSettings->alpha);
+ const auto blurSettings = layers[2];
+ EXPECT_TRUE(blurSettings.skipContentDraw);
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings.source.solidColor);
+ EXPECT_EQ(0.0f, blurSettings.alpha);
return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 3397118..fd09ae4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -466,9 +466,9 @@
return false;
}
-void DisplayDevice::onInvalidate() {
+void DisplayDevice::animateRefreshRateOverlay() {
if (mRefreshRateOverlay) {
- mRefreshRateOverlay->onInvalidate();
+ mRefreshRateOverlay->animate();
}
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 4a731bd..4b9718f 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -234,7 +234,7 @@
void enableRefreshRateOverlay(bool enable, bool showSpinner);
bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
- void onInvalidate();
+ void animateRefreshRateOverlay();
void onVsync(nsecs_t timestamp);
nsecs_t getVsyncPeriodFromHWC() const;
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/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index bb2888e..02d0658 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -166,4 +166,15 @@
}
}
+inline std::string to_string(hardware::graphics::composer::hal::Vsync vsync) {
+ switch (vsync) {
+ case hardware::graphics::composer::hal::Vsync::ENABLE:
+ return "Enable";
+ case hardware::graphics::composer::hal::Vsync::DISABLE:
+ return "Disable";
+ default:
+ return "Unknown";
+ }
+}
+
} // namespace android
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/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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 87afa22..388181c 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))) {
@@ -207,7 +207,8 @@
* Layer. So, the implementation is done in BufferLayer. When called on a
* EffectLayer object, it's essentially a NOP.
*/
-void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
+void Layer::onLayerDisplayed(
+ std::shared_future<renderengine::RenderEngineResult> /*futureRenderEngineResult*/) {}
void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
if (mDrawingState.zOrderRelativeOf == nullptr) {
@@ -426,20 +427,6 @@
void Layer::prepareGeometryCompositionState() {
const auto& drawingState{getDrawingState()};
-
- int type = drawingState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
- int appId = drawingState.metadata.getInt32(METADATA_OWNER_UID, 0);
- sp<Layer> parent = mDrawingParent.promote();
- if (parent.get()) {
- auto& parentState = parent->getDrawingState();
- const int parentType = parentState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
- const int parentAppId = parentState.metadata.getInt32(METADATA_OWNER_UID, 0);
- if (parentType > 0 && parentAppId > 0) {
- type = parentType;
- appId = parentAppId;
- }
- }
-
auto* compositionState = editCompositionState();
compositionState->geomBufferSize = getBufferSize(drawingState);
@@ -1136,7 +1123,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
@@ -1936,8 +1923,9 @@
Rect layerCropRect = getCroppedBufferSize(getDrawingState());
const float radius = getDrawingState().cornerRadius;
RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
+ const bool layerSettingsValid = layerSettings.radius > 0 && layerCropRect.isValid();
- if (layerSettings.radius > 0 && parentSettings.radius > 0) {
+ if (layerSettingsValid && parentSettings.radius > 0) {
// If the parent and the layer have rounded corner settings, use the parent settings if the
// parent crop is entirely inside the layer crop.
// This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
@@ -1949,7 +1937,7 @@
} else {
return layerSettings;
}
- } else if (layerSettings.radius > 0) {
+ } else if (layerSettingsValid) {
return layerSettings;
} else if (parentSettings.radius > 0) {
return parentSettings;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d17c05b..bf338c1 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -525,12 +525,10 @@
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- virtual bool onPostComposition(const DisplayDevice*,
+ virtual void onPostComposition(const DisplayDevice*,
const std::shared_ptr<FenceTime>& /*glDoneFence*/,
const std::shared_ptr<FenceTime>& /*presentFence*/,
- const CompositorTiming&) {
- return false;
- }
+ const CompositorTiming&) {}
// If a buffer was replaced this frame, release the former buffer
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
@@ -591,10 +589,6 @@
}
virtual FrameRate getFrameRateForLayerTree() const;
- virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) {
- return {};
- }
-
virtual bool getTransformToDisplayInverse() const { return false; }
// Returns how rounded corners should be drawn for this layer.
@@ -622,7 +616,8 @@
void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
- void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+ void onLayerDisplayed(
+ std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
void setWasClientComposed(const sp<Fence>& fence) override {
mLastClientCompositionFence = fence;
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 1062126..ee23561 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -53,28 +53,52 @@
return;
}
+ writeToProto(region, getRegionProto());
+}
+
+void LayerProtoHelper::writeToProto(const Region& region, RegionProto* regionProto) {
+ if (region.isEmpty()) {
+ return;
+ }
+
Region::const_iterator head = region.begin();
Region::const_iterator const tail = region.end();
// Use a lambda do avoid writing the object header when the object is empty
- RegionProto* regionProto = getRegionProto();
while (head != tail) {
- std::function<RectProto*()> getProtoRect = [&]() { return regionProto->add_rect(); };
- writeToProto(*head, getProtoRect);
+ writeToProto(*head, regionProto->add_rect());
head++;
}
}
+void LayerProtoHelper::readFromProto(const RegionProto& regionProto, Region& outRegion) {
+ for (int i = 0; i < regionProto.rect_size(); i++) {
+ Rect rect;
+ readFromProto(regionProto.rect(i), rect);
+ outRegion.orSelf(rect);
+ }
+}
+
void LayerProtoHelper::writeToProto(const Rect& rect, std::function<RectProto*()> getRectProto) {
if (rect.left != 0 || rect.right != 0 || rect.top != 0 || rect.bottom != 0) {
// Use a lambda do avoid writing the object header when the object is empty
- RectProto* rectProto = getRectProto();
- rectProto->set_left(rect.left);
- rectProto->set_top(rect.top);
- rectProto->set_bottom(rect.bottom);
- rectProto->set_right(rect.right);
+ writeToProto(rect, getRectProto());
}
}
+void LayerProtoHelper::writeToProto(const Rect& rect, RectProto* rectProto) {
+ rectProto->set_left(rect.left);
+ rectProto->set_top(rect.top);
+ rectProto->set_bottom(rect.bottom);
+ rectProto->set_right(rect.right);
+}
+
+void LayerProtoHelper::readFromProto(const RectProto& proto, Rect& outRect) {
+ outRect.left = proto.left();
+ outRect.top = proto.top();
+ outRect.bottom = proto.bottom();
+ outRect.right = proto.right();
+}
+
void LayerProtoHelper::writeToProto(const FloatRect& rect,
std::function<FloatRectProto*()> getFloatRectProto) {
if (rect.left != 0 || rect.right != 0 || rect.top != 0 || rect.bottom != 0) {
@@ -189,6 +213,39 @@
}
}
+void LayerProtoHelper::readFromProto(const ColorTransformProto& colorTransformProto, mat4& matrix) {
+ for (int i = 0; i < mat4::ROW_SIZE; i++) {
+ for (int j = 0; j < mat4::COL_SIZE; j++) {
+ matrix[i][j] = colorTransformProto.val(i * mat4::COL_SIZE + j);
+ }
+ }
+}
+
+void LayerProtoHelper::writeToProto(const android::BlurRegion region, BlurRegion* proto) {
+ proto->set_blur_radius(region.blurRadius);
+ proto->set_corner_radius_tl(region.cornerRadiusTL);
+ proto->set_corner_radius_tr(region.cornerRadiusTR);
+ proto->set_corner_radius_bl(region.cornerRadiusBL);
+ proto->set_corner_radius_br(region.cornerRadiusBR);
+ proto->set_alpha(region.alpha);
+ proto->set_left(region.left);
+ proto->set_top(region.top);
+ proto->set_right(region.right);
+ proto->set_bottom(region.bottom);
+}
+
+void LayerProtoHelper::readFromProto(const BlurRegion& proto, android::BlurRegion& outRegion) {
+ outRegion.blurRadius = proto.blur_radius();
+ outRegion.cornerRadiusTL = proto.corner_radius_tl();
+ outRegion.cornerRadiusTR = proto.corner_radius_tr();
+ outRegion.cornerRadiusBL = proto.corner_radius_bl();
+ outRegion.cornerRadiusBR = proto.corner_radius_br();
+ outRegion.alpha = proto.alpha();
+ outRegion.left = proto.left();
+ outRegion.top = proto.top();
+ outRegion.right = proto.right();
+ outRegion.bottom = proto.bottom();
+}
} // namespace surfaceflinger
} // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 36e0647..249ec42 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -19,6 +19,7 @@
#include <Layer.h>
#include <gui/WindowInfo.h>
#include <math/vec4.h>
+#include <ui/BlurRegion.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -33,9 +34,13 @@
static void writeSizeToProto(const uint32_t w, const uint32_t h,
std::function<SizeProto*()> getSizeProto);
static void writeToProto(const Rect& rect, std::function<RectProto*()> getRectProto);
+ static void writeToProto(const Rect& rect, RectProto* rectProto);
+ static void readFromProto(const RectProto& proto, Rect& outRect);
static void writeToProto(const FloatRect& rect,
std::function<FloatRectProto*()> getFloatRectProto);
static void writeToProto(const Region& region, std::function<RegionProto*()> getRegionProto);
+ static void writeToProto(const Region& region, RegionProto* regionProto);
+ static void readFromProto(const RegionProto& regionProto, Region& outRegion);
static void writeToProto(const half4 color, std::function<ColorProto*()> getColorProto);
// This writeToProto for transform is incorrect, but due to backwards compatibility, we can't
// update Layers to use it. Use writeTransformToProto for any new transform proto data.
@@ -49,6 +54,9 @@
const wp<Layer>& touchableRegionBounds,
std::function<InputWindowInfoProto*()> getInputWindowInfoProto);
static void writeToProto(const mat4 matrix, ColorTransformProto* colorTransformProto);
+ static void readFromProto(const ColorTransformProto& colorTransformProto, mat4& matrix);
+ static void writeToProto(const android::BlurRegion region, BlurRegion*);
+ static void readFromProto(const BlurRegion& proto, android::BlurRegion& outRegion);
};
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index ec81e63..2502d66 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -284,7 +284,7 @@
t.apply();
}
-void RefreshRateOverlay::onInvalidate() {
+void RefreshRateOverlay::animate() {
if (!mCurrentFps.has_value()) return;
const auto& buffers = getOrCreateBuffers(*mCurrentFps);
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 354510a..65d446c 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -46,7 +46,7 @@
void setLayerStack(ui::LayerStack);
void setViewport(ui::Size);
void changeRefreshRate(const Fps&);
- void onInvalidate();
+ void animate();
private:
class SevenSegmentDrawer {
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index aa2fec5..32585dd 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -150,7 +150,7 @@
if (mSampleRequestTime.has_value()) {
ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase));
mSampleRequestTime.reset();
- mFlinger.scheduleRegionSamplingThread();
+ mFlinger.scheduleSample();
}
}
@@ -356,10 +356,13 @@
renderengine::ExternalTexture::Usage::WRITEABLE);
}
- const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
- true /* regionSampling */, false /* grayscale */, captureListener);
- ScreenCaptureResults captureResults = captureListener->waitForResults();
+ auto captureScreenResultFuture =
+ mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+ true /* regionSampling */, false /* grayscale */, nullptr);
+ auto& captureScreenResult = captureScreenResultFuture.get();
+ if (captureScreenResult.drawFence.ok()) {
+ sync_wait(captureScreenResult.drawFence.get(), -1);
+ }
std::vector<Descriptor> activeDescriptors;
for (const auto& descriptor : descriptors) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 2bdcaf6..e07eae7 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -355,14 +355,7 @@
std::lock_guard<std::mutex> lock(mMutex);
LOG_FATAL_IF(!mVSyncState);
- const int64_t vsyncId = [&] {
- if (mTokenManager != nullptr) {
- return mTokenManager->generateTokenForPredictions(
- {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
- }
- return FrameTimelineInfo::INVALID_VSYNC_ID;
- }();
-
+ const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp);
mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
expectedVSyncTimestamp, deadlineTimestamp, vsyncId));
mCondition.notify_all();
@@ -567,12 +560,48 @@
}
}
+int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
+ nsecs_t deadlineTimestamp) const {
+ if (mTokenManager != nullptr) {
+ return mTokenManager->generateTokenForPredictions(
+ {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
+ }
+ return FrameTimelineInfo::INVALID_VSYNC_ID;
+}
+
+void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const {
+ // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included.
+ for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0;
+ currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) {
+ nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval;
+ // Valid possible frame timelines must have future values.
+ if (deadline > event.header.timestamp) {
+ if (multiplier == 0) {
+ event.vsync.preferredFrameTimelineIndex = currentIndex;
+ event.vsync.frameTimelines[currentIndex] =
+ {.vsyncId = event.vsync.vsyncId,
+ .deadlineTimestamp = event.vsync.deadlineTimestamp,
+ .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp};
+ } else {
+ nsecs_t expectedVSync =
+ event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval;
+ event.vsync.frameTimelines[currentIndex] =
+ {.vsyncId = generateToken(event.header.timestamp, expectedVSync, deadline),
+ .deadlineTimestamp = deadline,
+ .expectedVSyncTimestamp = expectedVSync};
+ }
+ currentIndex++;
+ }
+ }
+}
+
void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
const DisplayEventConsumers& consumers) {
for (const auto& consumer : consumers) {
DisplayEventReceiver::Event copy = event;
if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
+ generateFrameTimeline(copy);
}
switch (consumer->postEvent(copy)) {
case NO_ERROR:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 9265a25..73ae5dc 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -204,6 +204,10 @@
void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
nsecs_t deadlineTimestamp) override;
+ int64_t generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
+ nsecs_t deadlineTimestamp) const;
+ void generateFrameTimeline(DisplayEventReceiver::Event& event) const;
+
const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
frametimeline::TokenManager* const mTokenManager;
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/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 4d51125..043a536 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -27,49 +27,55 @@
#include "EventThread.h"
#include "FrameTimeline.h"
#include "MessageQueue.h"
-#include "SurfaceFlinger.h"
namespace android::impl {
-void MessageQueue::Handler::dispatchRefresh() {
- if ((mEventMask.fetch_or(eventMaskRefresh) & eventMaskRefresh) == 0) {
- mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
+void MessageQueue::Handler::dispatchComposite() {
+ if ((mEventMask.fetch_or(kComposite) & kComposite) == 0) {
+ mQueue.mLooper->sendMessage(this, Message(kComposite));
}
}
-void MessageQueue::Handler::dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp) {
- if ((mEventMask.fetch_or(eventMaskInvalidate) & eventMaskInvalidate) == 0) {
+void MessageQueue::Handler::dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime) {
+ if ((mEventMask.fetch_or(kCommit) & kCommit) == 0) {
mVsyncId = vsyncId;
- mExpectedVSyncTime = expectedVSyncTimestamp;
- mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
+ mExpectedVsyncTime = expectedVsyncTime;
+ mQueue.mLooper->sendMessage(this, Message(kCommit));
}
}
-bool MessageQueue::Handler::invalidatePending() {
- constexpr auto pendingMask = eventMaskInvalidate | eventMaskRefresh;
- return (mEventMask.load() & pendingMask) != 0;
+bool MessageQueue::Handler::isFramePending() const {
+ constexpr auto kPendingMask = kCommit | kComposite;
+ return (mEventMask.load() & kPendingMask) != 0;
}
void MessageQueue::Handler::handleMessage(const Message& message) {
+ const nsecs_t frameTime = systemTime();
switch (message.what) {
- case INVALIDATE:
- mEventMask.fetch_and(~eventMaskInvalidate);
- mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
- break;
- case REFRESH:
- mEventMask.fetch_and(~eventMaskRefresh);
- mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
+ case kCommit:
+ mEventMask.fetch_and(~kCommit);
+ if (!mQueue.mCompositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {
+ return;
+ }
+ // Composite immediately, rather than after pending tasks through scheduleComposite.
+ [[fallthrough]];
+ case kComposite:
+ mEventMask.fetch_and(~kComposite);
+ mQueue.mCompositor.composite(frameTime);
+ mQueue.mCompositor.sample();
break;
}
}
-// ---------------------------------------------------------------------------
+MessageQueue::MessageQueue(ICompositor& compositor)
+ : MessageQueue(compositor, sp<Handler>::make(*this)) {}
-void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
- mFlinger = flinger;
- mLooper = new Looper(true);
- mHandler = new Handler(*this);
-}
+constexpr bool kAllowNonCallbacks = true;
+
+MessageQueue::MessageQueue(ICompositor& compositor, sp<Handler> handler)
+ : mCompositor(compositor),
+ mLooper(sp<Looper>::make(kAllowNonCallbacks)),
+ mHandler(std::move(handler)) {}
// TODO(b/169865816): refactor VSyncInjections to use MessageQueue directly
// and remove the EventThread from MessageQueue
@@ -110,11 +116,13 @@
{
std::lock_guard lock(mVsync.mutex);
mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime);
- mVsync.scheduled = false;
+ mVsync.scheduledFrameTime.reset();
}
- mHandler->dispatchInvalidate(mVsync.tokenManager->generateTokenForPredictions(
- {targetWakeupTime, readyTime, vsyncTime}),
- vsyncTime);
+
+ const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions(
+ {targetWakeupTime, readyTime, vsyncTime});
+
+ mHandler->dispatchCommit(vsyncId, vsyncTime);
}
void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
@@ -135,8 +143,8 @@
ATRACE_CALL();
std::lock_guard lock(mVsync.mutex);
mVsync.workDuration = workDuration;
- if (mVsync.scheduled) {
- mVsync.expectedWakeupTime = mVsync.registration->schedule(
+ if (mVsync.scheduledFrameTime) {
+ mVsync.scheduledFrameTime = mVsync.registration->schedule(
{mVsync.workDuration.get().count(),
/*readyDuration=*/0, mVsync.lastCallbackTime.count()});
}
@@ -168,7 +176,7 @@
mLooper->sendMessage(handler, Message());
}
-void MessageQueue::invalidate() {
+void MessageQueue::scheduleCommit() {
ATRACE_CALL();
{
@@ -181,15 +189,14 @@
}
std::lock_guard lock(mVsync.mutex);
- mVsync.scheduled = true;
- mVsync.expectedWakeupTime =
+ mVsync.scheduledFrameTime =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.earliestVsync = mVsync.lastCallbackTime.count()});
}
-void MessageQueue::refresh() {
- mHandler->dispatchRefresh();
+void MessageQueue::scheduleComposite() {
+ mHandler->dispatchComposite();
}
void MessageQueue::injectorCallback() {
@@ -198,24 +205,22 @@
while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) {
for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- mHandler->dispatchInvalidate(buffer[i].vsync.vsyncId,
- buffer[i].vsync.expectedVSyncTimestamp);
+ mHandler->dispatchCommit(buffer[i].vsync.vsyncId,
+ buffer[i].vsync.expectedVSyncTimestamp);
break;
}
}
}
}
-std::optional<std::chrono::steady_clock::time_point> MessageQueue::nextExpectedInvalidate() {
- if (mHandler->invalidatePending()) {
- return std::chrono::steady_clock::now();
+auto MessageQueue::getScheduledFrameTime() const -> std::optional<Clock::time_point> {
+ if (mHandler->isFramePending()) {
+ return Clock::now();
}
std::lock_guard lock(mVsync.mutex);
- if (mVsync.scheduled) {
- LOG_ALWAYS_FATAL_IF(!mVsync.expectedWakeupTime.has_value(), "callback was never scheduled");
- const auto expectedWakeupTime = std::chrono::nanoseconds(*mVsync.expectedWakeupTime);
- return std::optional<std::chrono::steady_clock::time_point>(expectedWakeupTime);
+ if (const auto time = mVsync.scheduledFrameTime) {
+ return Clock::time_point(std::chrono::nanoseconds(*time));
}
return std::nullopt;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 58ce9b9..2c908a6 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -33,7 +33,14 @@
namespace android {
-class SurfaceFlinger;
+struct ICompositor {
+ virtual bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) = 0;
+ virtual void composite(nsecs_t frameTime) = 0;
+ virtual void sample() = 0;
+
+protected:
+ ~ICompositor() = default;
+};
template <typename F>
class Task : public MessageHandler {
@@ -56,65 +63,65 @@
class MessageQueue {
public:
- enum {
- INVALIDATE = 0,
- REFRESH = 1,
- };
-
virtual ~MessageQueue() = default;
- virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
virtual void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
std::chrono::nanoseconds workDuration) = 0;
virtual void setDuration(std::chrono::nanoseconds workDuration) = 0;
virtual void setInjector(sp<EventThreadConnection>) = 0;
virtual void waitMessage() = 0;
virtual void postMessage(sp<MessageHandler>&&) = 0;
- virtual void invalidate() = 0;
- virtual void refresh() = 0;
- virtual std::optional<std::chrono::steady_clock::time_point> nextExpectedInvalidate() = 0;
-};
+ virtual void scheduleCommit() = 0;
+ virtual void scheduleComposite() = 0;
-// ---------------------------------------------------------------------------
+ using Clock = std::chrono::steady_clock;
+ virtual std::optional<Clock::time_point> getScheduledFrameTime() const = 0;
+};
namespace impl {
class MessageQueue : public android::MessageQueue {
protected:
class Handler : public MessageHandler {
- enum : uint32_t {
- eventMaskInvalidate = 0x1,
- eventMaskRefresh = 0x2,
- eventMaskTransaction = 0x4
- };
+ static constexpr uint32_t kCommit = 0b1;
+ static constexpr uint32_t kComposite = 0b10;
+
MessageQueue& mQueue;
- std::atomic<uint32_t> mEventMask;
- std::atomic<int64_t> mVsyncId;
- std::atomic<nsecs_t> mExpectedVSyncTime;
+ std::atomic<uint32_t> mEventMask = 0;
+ std::atomic<int64_t> mVsyncId = 0;
+ std::atomic<nsecs_t> mExpectedVsyncTime = 0;
public:
- explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
+ explicit Handler(MessageQueue& queue) : mQueue(queue) {}
void handleMessage(const Message& message) override;
- virtual void dispatchRefresh();
- virtual void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp);
- virtual bool invalidatePending();
+
+ bool isFramePending() const;
+
+ virtual void dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime);
+ void dispatchComposite();
};
friend class Handler;
- sp<SurfaceFlinger> mFlinger;
- sp<Looper> mLooper;
+ // For tests.
+ MessageQueue(ICompositor&, sp<Handler>);
+
+ void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
+
+private:
+ ICompositor& mCompositor;
+ const sp<Looper> mLooper;
+ const sp<Handler> mHandler;
struct Vsync {
frametimeline::TokenManager* tokenManager = nullptr;
std::unique_ptr<scheduler::VSyncCallbackRegistration> registration;
- std::mutex mutex;
+ mutable std::mutex mutex;
TracedOrdinal<std::chrono::nanoseconds> workDuration
GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0};
- bool scheduled GUARDED_BY(mutex) = false;
- std::optional<nsecs_t> expectedWakeupTime GUARDED_BY(mutex);
+ std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex);
TracedOrdinal<int> value = {"VSYNC-sf", 0};
};
@@ -127,14 +134,11 @@
Vsync mVsync;
Injector mInjector;
- sp<Handler> mHandler;
-
- void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
void injectorCallback();
public:
- ~MessageQueue() override = default;
- void init(const sp<SurfaceFlinger>& flinger) override;
+ explicit MessageQueue(ICompositor&);
+
void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
std::chrono::nanoseconds workDuration) override;
void setDuration(std::chrono::nanoseconds workDuration) override;
@@ -143,13 +147,10 @@
void waitMessage() override;
void postMessage(sp<MessageHandler>&&) override;
- // sends INVALIDATE message at next VSYNC
- void invalidate() override;
+ void scheduleCommit() override;
+ void scheduleComposite() override;
- // sends REFRESH message at next VSYNC
- void refresh() override;
-
- std::optional<std::chrono::steady_clock::time_point> nextExpectedInvalidate() override;
+ std::optional<Clock::time_point> getScheduledFrameTime() const override;
};
} // namespace impl
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 12e741b..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;
}
}
@@ -324,6 +324,7 @@
thread = mConnections[handle].thread.get();
}
thread->onScreenAcquired();
+ mScreenAcquired = true;
}
void Scheduler::onScreenReleased(ConnectionHandle handle) {
@@ -334,6 +335,7 @@
thread = mConnections[handle].thread.get();
}
thread->onScreenReleased();
+ mScreenAcquired = false;
}
void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
@@ -697,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.
@@ -760,6 +763,13 @@
}
StringAppendF(&result, "}\n");
}
+
+ {
+ std::lock_guard lock(mHWVsyncLock);
+ StringAppendF(&result,
+ "mScreenAcquired=%d mPrimaryHWVsyncEnabled=%d mHWVsyncAvailable=%d\n",
+ mScreenAcquired.load(), mPrimaryHWVsyncEnabled, mHWVsyncAvailable);
+ }
}
void Scheduler::dumpVsync(std::string& s) const {
@@ -781,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;
@@ -870,7 +879,7 @@
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
if (timeline.refreshRequired) {
- mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
+ mSchedulerCallback.scheduleComposite(FrameHint::kNone);
}
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
@@ -882,12 +891,12 @@
}
}
-void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
- const bool refresh = [=] {
+void Scheduler::onPostComposition(nsecs_t presentTime) {
+ const bool recomposite = [=] {
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
- if (timestamp < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
- // We need to schedule another refresh as refreshTimeNanos is still in the future.
+ if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
+ // We need to composite again as refreshTimeNanos is still in the future.
return true;
}
@@ -896,8 +905,8 @@
return false;
}();
- if (refresh) {
- mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
+ if (recomposite) {
+ mSchedulerCallback.scheduleComposite(FrameHint::kNone);
}
}
@@ -912,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/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 3f3debe..8397738 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -59,7 +59,7 @@
// Indicates frame activity, i.e. whether commit and/or composite is taking place.
enum class FrameHint { kNone, kActive };
- virtual void scheduleRefresh(FrameHint) = 0;
+ virtual void scheduleComposite(FrameHint) = 0;
virtual void setVsyncEnabled(bool) = 0;
virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent) = 0;
@@ -162,8 +162,8 @@
// Notifies the scheduler about a refresh rate timeline change.
void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
- // Notifies the scheduler when the display was refreshed
- void onDisplayRefreshed(nsecs_t timestamp);
+ // Notifies the scheduler post composition.
+ void onPostComposition(nsecs_t presentTime);
// Notifies the scheduler when the display size has changed. Called from SF's main thread
void onActiveDisplayAreaChanged(uint32_t displayArea);
@@ -287,7 +287,7 @@
InjectVSyncSource* mVSyncInjector = nullptr;
ConnectionHandle mInjectorConnectionHandle;
- std::mutex mHWVsyncLock;
+ mutable std::mutex mHWVsyncLock;
bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false;
bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false;
@@ -350,6 +350,9 @@
GUARDED_BY(mFrameRateOverridesLock);
scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor
GUARDED_BY(mFrameRateOverridesLock);
+
+ // Keeps track of whether the screen is acquired for debug
+ std::atomic<bool> mScreenAcquired = false;
};
} // namespace android
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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e90af3a..8d7221c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -371,7 +371,7 @@
mTimeStats(std::make_shared<impl::TimeStats>()),
mFrameTracer(mFactory.createFrameTracer()),
mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())),
- mEventQueue(mFactory.createMessageQueue()),
+ mEventQueue(mFactory.createMessageQueue(*this)),
mCompositionEngine(mFactory.createCompositionEngine()),
mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
@@ -506,10 +506,6 @@
SurfaceFlinger::~SurfaceFlinger() = default;
-void SurfaceFlinger::onFirstRef() {
- mEventQueue->init(this);
-}
-
void SurfaceFlinger::binderDied(const wp<IBinder>&) {
// the window manager died on us. prepare its eulogy.
mBootFinished = false;
@@ -713,6 +709,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();
@@ -1043,7 +1040,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();
@@ -1104,7 +1101,7 @@
}
if (display->setDesiredActiveMode(info)) {
- scheduleRefresh(FrameHint::kNone);
+ scheduleComposite(FrameHint::kNone);
// Start receiving vsync samples now, so that we can detect a period
// switch.
@@ -1704,31 +1701,26 @@
return mScheduler->createDisplayEventConnection(handle, eventRegistration);
}
-void SurfaceFlinger::scheduleInvalidate(FrameHint hint) {
+void SurfaceFlinger::scheduleCommit(FrameHint hint) {
if (hint == FrameHint::kActive) {
mScheduler->resetIdleTimer();
}
mPowerAdvisor.notifyDisplayUpdateImminent();
- mEventQueue->invalidate();
+ mEventQueue->scheduleCommit();
}
-void SurfaceFlinger::scheduleRefresh(FrameHint hint) {
- mForceRefresh = true;
- scheduleInvalidate(hint);
+void SurfaceFlinger::scheduleComposite(FrameHint hint) {
+ mMustComposite = true;
+ scheduleCommit(hint);
}
void SurfaceFlinger::scheduleRepaint() {
mGeometryDirty = true;
- scheduleRefresh(FrameHint::kActive);
+ scheduleComposite(FrameHint::kActive);
}
-void SurfaceFlinger::signalLayerUpdate() {
- scheduleInvalidate(FrameHint::kActive);
-}
-
-void SurfaceFlinger::signalRefresh() {
- mRefreshPending = true;
- mEventQueue->refresh();
+void SurfaceFlinger::scheduleSample() {
+ static_cast<void>(schedule([this] { sample(); }));
}
nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
@@ -1834,7 +1826,7 @@
void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) {
Mutex::Autolock lock(mStateLock);
- scheduleRefresh(FrameHint::kNone);
+ scheduleComposite(FrameHint::kNone);
}
void SurfaceFlinger::setVsyncEnabled(bool enabled) {
@@ -1846,7 +1838,7 @@
if (const auto display = getDefaultDisplayDeviceLocked();
display && display->isPoweredOn()) {
- getHwComposer().setVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState);
+ setHWCVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState);
}
}));
}
@@ -1889,40 +1881,26 @@
: stats.vsyncTime + stats.vsyncPeriod;
}
-void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) {
- switch (what) {
- case MessageQueue::INVALIDATE: {
- onMessageInvalidate(vsyncId, expectedVSyncTime);
- break;
- }
- case MessageQueue::REFRESH: {
- onMessageRefresh();
- break;
- }
- }
-}
-
-void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime) {
- const nsecs_t frameStart = systemTime();
+bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) {
// calculate the expected present time once and use the cached
// value throughout this frame to make sure all layers are
// seeing this same value.
- if (expectedVSyncTime >= frameStart) {
- mExpectedPresentTime = expectedVSyncTime;
+ if (expectedVsyncTime >= frameTime) {
+ mExpectedPresentTime = expectedVsyncTime;
} else {
- const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameStart);
+ const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameTime);
mExpectedPresentTime = calculateExpectedPresentTime(stats);
}
const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
- mScheduledPresentTime = expectedVSyncTime;
+ mScheduledPresentTime = expectedVsyncTime;
const auto vsyncIn = [&] {
if (!ATRACE_ENABLED()) return 0.f;
return (mExpectedPresentTime - systemTime()) / 1e6f;
}();
- ATRACE_FORMAT("onMessageInvalidate %" PRId64 " vsyncIn %.2fms%s", vsyncId, vsyncIn,
- mExpectedPresentTime == expectedVSyncTime ? "" : " (adjusted)");
+ ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn,
+ mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)");
// When Backpressure propagation is enabled we want to give a small grace period
// for the present fence to fire instead of just giving up on this frame to handle cases
@@ -1969,11 +1947,11 @@
}
// If we are in the middle of a mode change and the fence hasn't
- // fired yet just wait for the next invalidate
+ // fired yet just wait for the next commit.
if (mSetActiveModePending) {
if (framePending) {
- mEventQueue->invalidate();
- return;
+ mEventQueue->scheduleCommit();
+ return false;
}
// We received the present fence from the HWC, so we assume it successfully updated
@@ -1984,8 +1962,8 @@
if (framePending) {
if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) {
- signalLayerUpdate();
- return;
+ scheduleCommit(FrameHint::kNone);
+ return false;
}
}
@@ -1997,11 +1975,12 @@
if (mRefreshRateOverlaySpinner) {
Mutex::Autolock lock(mStateLock);
if (const auto display = getDefaultDisplayDeviceLocked()) {
- display->onInvalidate();
+ display->animateRefreshRateOverlay();
}
}
- bool refreshNeeded = mForceRefresh.exchange(false);
+ // Composite if transactions were committed, or if requested by HWC.
+ bool mustComposite = mMustComposite.exchange(false);
{
mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
@@ -2009,10 +1988,12 @@
const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
- mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod));
+ mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod));
- refreshNeeded |= flushAndCommitTransactions();
- refreshNeeded |= handleMessageInvalidate();
+ mustComposite |= flushAndCommitTransactions();
+ mustComposite |= latchBuffers();
+
+ updateLayerGeometry();
if (tracePreComposition) {
if (mVisibleRegionsDirty) {
@@ -2035,39 +2016,30 @@
updateCursorAsync();
updateInputFlinger();
- if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
- // Signal a refresh if a transaction modified the window state,
- // a new buffer was latched, or if HWC has requested a full
- // repaint
- if (mFrameStartTime <= 0) {
- // We should only use the time of the first invalidate
- // message that signals a refresh as the beginning of the
- // frame. Otherwise the real frame time will be
- // underestimated.
- mFrameStartTime = frameStart;
- }
-
- // Run the refresh immediately after invalidate as there is no point going thru the message
- // queue again, and to ensure that we actually refresh the screen instead of handling
- // other messages that were queued us already in the MessageQueue.
- mRefreshPending = true;
- onMessageRefresh();
- }
- notifyRegionSamplingThread();
+ return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
bool SurfaceFlinger::flushAndCommitTransactions() {
ATRACE_CALL();
+ bool needsTraversal = false;
if (clearTransactionFlags(eTransactionFlushNeeded)) {
- flushTransactionQueues();
+ needsTraversal = flushTransactionQueues();
}
- const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || mForceTraversal;
+ const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
if (shouldCommit) {
commitTransactions();
}
+ if (!needsTraversal) {
+ // Invoke empty transaction callbacks early.
+ mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
+ } else {
+ // Invoke OnCommit callbacks.
+ mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */);
+ }
+
if (transactionFlushNeeded()) {
setTransactionFlags(eTransactionFlushNeeded);
}
@@ -2075,11 +2047,9 @@
return shouldCommit;
}
-void SurfaceFlinger::onMessageRefresh() {
+void SurfaceFlinger::composite(nsecs_t frameTime) {
ATRACE_CALL();
- mRefreshPending = false;
-
compositionengine::CompositionRefreshArgs refreshArgs;
const auto& displays = ON_MAIN_THREAD(mDisplays);
refreshArgs.outputs.reserve(displays.size());
@@ -2123,18 +2093,16 @@
const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
- refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate();
+ refreshArgs.scheduledFrameTime = mEventQueue->getScheduledFrameTime();
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
const auto presentTime = systemTime();
mCompositionEngine->present(refreshArgs);
- mTimeStats->recordFrameDuration(mFrameStartTime, systemTime());
- // Reset the frame start time now that we've recorded this frame.
- mFrameStartTime = 0;
+ mTimeStats->recordFrameDuration(frameTime, systemTime());
- mScheduler->onDisplayRefreshed(presentTime);
+ mScheduler->onPostComposition(presentTime);
postFrame();
postComposition();
@@ -2177,17 +2145,12 @@
mVisibleRegionsDirty = false;
if (mCompositionEngine->needsAnotherUpdate()) {
- signalLayerUpdate();
+ scheduleCommit(FrameHint::kNone);
}
}
-bool SurfaceFlinger::handleMessageInvalidate() {
+void SurfaceFlinger::updateLayerGeometry() {
ATRACE_CALL();
- // Send on commit callbacks
- mTransactionCallbackInvoker.sendCallbacks();
-
- bool refreshNeeded = handlePageFlip();
-
if (mVisibleRegionsDirty) {
computeLayerBounds();
@@ -2199,7 +2162,6 @@
invalidateLayerStack(layer, visibleReg);
}
mLayersPendingRefresh.clear();
- return refreshNeeded;
}
void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
@@ -2308,13 +2270,9 @@
}
for (const auto& layer: mLayersWithQueuedFrames) {
- const bool frameLatched =
- layer->onPostComposition(display, glCompositionDoneFenceTime,
- mPreviousPresentFences[0].fenceTime, compositorTiming);
+ layer->onPostComposition(display, glCompositionDoneFenceTime,
+ mPreviousPresentFences[0].fenceTime, compositorTiming);
layer->releasePendingBuffer(/*dequeueReadyTime*/ now);
- if (frameLatched) {
- recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false));
- }
}
std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>>
@@ -2377,7 +2335,7 @@
mVisibleRegionsWereDirtyThisFrame = false;
mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
- mTransactionCallbackInvoker.sendCallbacks();
+ mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
mTransactionCallbackInvoker.clearCompletedTransactions();
if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON &&
@@ -2990,7 +2948,6 @@
processDisplayChangesLocked();
processDisplayHotplugEventsLocked();
}
- mForceTraversal = false;
mForceTransactionDisplayChange = displayTransactionNeeded;
if (mSomeChildrenChanged) {
@@ -3100,20 +3057,29 @@
bool enablePerWindowInputRotation() {
static bool value =
- android::base::GetBoolProperty("persist.debug.per_window_input_rotation", false);
+ android::base::GetBoolProperty("persist.debug.per_window_input_rotation", true);
return value;
}
void SurfaceFlinger::notifyWindowInfos() {
std::vector<WindowInfo> windowInfos;
std::vector<DisplayInfo> displayInfos;
- std::unordered_map<const DisplayDevice*, const ui::Transform> displayTransforms;
+ std::unordered_map<uint32_t /*layerStackId*/, const ui::Transform> displayTransforms;
if (enablePerWindowInputRotation()) {
for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ if (!display->receivesInput()) {
+ continue;
+ }
+ const uint32_t layerStackId = display->getLayerStack().id;
const auto& [info, transform] = display->getInputInfo();
+ const auto& [it, emplaced] = displayTransforms.try_emplace(layerStackId, transform);
+ if (!emplaced) {
+ ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
+ layerStackId);
+ continue;
+ }
displayInfos.emplace_back(info);
- displayTransforms.emplace(display.get(), transform);
}
}
@@ -3123,10 +3089,10 @@
const DisplayDevice* display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get();
ui::Transform displayTransform = ui::Transform();
- if (enablePerWindowInputRotation()) {
+ if (enablePerWindowInputRotation() && display != nullptr) {
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- const auto it = displayTransforms.find(display);
+ const auto it = displayTransforms.find(display->getLayerStack().id);
if (it != displayTransforms.end()) {
displayTransform = it->second;
}
@@ -3244,8 +3210,6 @@
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (const auto& l : mLayersPendingRemoval) {
- recordBufferingStats(l->getName(), l->getOccupancyHistory(true));
-
// Ensure any buffers set to display on any children are released.
if (l->isRemovedFromCurrentState()) {
l->latchAndReleaseBuffer();
@@ -3301,11 +3265,10 @@
}
}
-bool SurfaceFlinger::handlePageFlip() {
+bool SurfaceFlinger::latchBuffers() {
ATRACE_CALL();
- ALOGV("handlePageFlip");
- nsecs_t latchTime = systemTime();
+ const nsecs_t latchTime = systemTime();
bool visibleRegions = false;
bool frameQueued = false;
@@ -3374,7 +3337,7 @@
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
- signalLayerUpdate();
+ scheduleCommit(FrameHint::kNone);
}
// enter boot animation on first buffer latch
@@ -3453,15 +3416,12 @@
const sp<IBinder>& applyToken) {
const uint32_t old = mTransactionFlags.fetch_or(mask);
modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
- if ((old & mask) == 0) scheduleInvalidate(FrameHint::kActive);
+ if ((old & mask) == 0) scheduleCommit(FrameHint::kActive);
return old;
}
-void SurfaceFlinger::setTraversalNeeded() {
- mForceTraversal = true;
-}
-
-void SurfaceFlinger::flushTransactionQueues() {
+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
@@ -3530,19 +3490,23 @@
// Now apply all transactions.
for (const auto& transaction : transactions) {
- 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);
+ 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));
}
}
- }
+ } // unlock mStateLock
+ return needsTraversal;
}
bool SurfaceFlinger::transactionFlushNeeded() {
@@ -3748,7 +3712,7 @@
return NO_ERROR;
}
-void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
+bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
@@ -3770,12 +3734,10 @@
mTransactionCallbackInvoker.addEmptyTransaction(listener);
}
- std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces;
uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
- clientStateFlags |=
- setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp,
- postTime, permissions, listenerCallbacksWithSurfaces);
+ clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime,
+ isAutoTimestamp, postTime, permissions);
if ((flags & eAnimation) && state.state.surface) {
if (const auto layer = fromHandle(state.state.surface).promote(); layer) {
mScheduler->recordLayerHistory(layer.get(),
@@ -3785,10 +3747,6 @@
}
}
- // If the state doesn't require a traversal and there are callbacks, send them now
- if (!(clientStateFlags & eTraversalNeeded) && hasListenerCallbacks) {
- mTransactionCallbackInvoker.sendCallbacks();
- }
transactionFlags |= clientStateFlags;
if (permissions & Permission::ACCESS_SURFACE_FLINGER) {
@@ -3810,6 +3768,7 @@
transactionFlags = eTransactionNeeded;
}
+ bool needsTraversal = false;
if (transactionFlags) {
if (mInterceptor->isEnabled()) {
mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
@@ -3820,7 +3779,7 @@
// so we don't have to wake up again next frame to preform an unnecessary traversal.
if (transactionFlags & eTraversalNeeded) {
transactionFlags = transactionFlags & (~eTraversalNeeded);
- mForceTraversal = true;
+ needsTraversal = true;
}
if (transactionFlags) {
setTransactionFlags(transactionFlags);
@@ -3830,6 +3789,8 @@
mAnimTransactionPending = true;
}
}
+
+ return needsTraversal;
}
uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
@@ -3898,10 +3859,10 @@
return true;
}
-uint32_t SurfaceFlinger::setClientStateLocked(
- const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState,
- int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions,
- std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& outListenerCallbacks) {
+uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTimelineInfo,
+ const ComposerState& composerState,
+ int64_t desiredPresentTime, bool isAutoTimestamp,
+ int64_t postTime, uint32_t permissions) {
const layer_state_t& s = composerState.state;
const bool privileged = permissions & Permission::ACCESS_SURFACE_FLINGER;
@@ -3915,13 +3876,11 @@
ListenerCallbacks onCommitCallbacks = listener.filter(CallbackId::Type::ON_COMMIT);
if (!onCommitCallbacks.callbackIds.empty()) {
filteredListeners.push_back(onCommitCallbacks);
- outListenerCallbacks.insert(onCommitCallbacks);
}
ListenerCallbacks onCompleteCallbacks = listener.filter(CallbackId::Type::ON_COMPLETE);
if (!onCompleteCallbacks.callbackIds.empty()) {
filteredListeners.push_back(onCompleteCallbacks);
- outListenerCallbacks.insert(onCompleteCallbacks);
}
}
@@ -4150,7 +4109,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;
}
}
@@ -4248,7 +4208,7 @@
sp<Layer> mirrorLayer;
sp<Layer> mirrorFrom;
- std::string uniqueName = getUniqueLayerName("MirrorRoot");
+ std::string layerName = "MirrorRoot";
{
Mutex::Autolock _l(mStateLock);
@@ -4257,7 +4217,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;
@@ -4291,12 +4251,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) {
@@ -4313,7 +4273,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:
@@ -4323,7 +4283,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:
@@ -4341,38 +4301,12 @@
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,
@@ -4544,6 +4478,12 @@
return;
}
+ const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
+ if (activeDisplay != display && display->isInternal() && activeDisplay &&
+ activeDisplay->isPoweredOn()) {
+ ALOGW("Trying to change power mode on non active display while the active display is ON");
+ }
+
display->setPowerMode(mode);
if (mInterceptor->isEnabled()) {
@@ -4551,7 +4491,7 @@
}
const auto vsyncPeriod = display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
if (currentMode == hal::PowerMode::OFF) {
- const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
+ // Turn on the display
if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
onActiveDisplayChangedLocked(display);
}
@@ -4564,15 +4504,15 @@
ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
}
getHwComposer().setPowerMode(displayId, mode);
- if (display->isInternal() && mode != hal::PowerMode::DOZE_SUSPEND) {
- getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState);
+ if (isDisplayActiveLocked(display) && mode != hal::PowerMode::DOZE_SUSPEND) {
+ setHWCVsyncEnabled(displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
}
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
- scheduleRefresh(FrameHint::kActive);
+ scheduleComposite(FrameHint::kActive);
} else if (mode == hal::PowerMode::OFF) {
// Turn off the display
if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) {
@@ -4581,13 +4521,13 @@
if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
}
- if (display->isInternal() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
+ if (isDisplayActiveLocked(display) && currentMode != hal::PowerMode::DOZE_SUSPEND) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
// Make sure HWVsync is disabled before turning off the display
- getHwComposer().setVsyncEnabled(displayId, hal::Vsync::DISABLE);
+ setHWCVsyncEnabled(displayId, hal::Vsync::DISABLE);
getHwComposer().setPowerMode(displayId, mode);
mVisibleRegionsDirty = true;
@@ -4595,13 +4535,13 @@
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (display->isInternal() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+ if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
- if (display->isInternal()) {
+ if (isDisplayActiveLocked(display)) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
@@ -4611,7 +4551,7 @@
getHwComposer().setPowerMode(displayId, mode);
}
- if (display->isInternal()) {
+ if (isDisplayActiveLocked(display)) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
@@ -4790,6 +4730,8 @@
mScheduler->dump(mAppConnectionHandle, result);
mScheduler->dumpVsync(result);
+ StringAppendF(&result, "mHWCVsyncPendingState=%s mLastHWCVsyncState=%s\n",
+ to_string(mHWCVsyncPendingState).c_str(), to_string(mLastHWCVsyncState).c_str());
}
void SurfaceFlinger::dumpPlannerInfo(const DumpArgs& args, std::string& result) const {
@@ -4814,24 +4756,6 @@
bucketTimeSec, percent);
}
-void SurfaceFlinger::recordBufferingStats(const std::string& layerName,
- std::vector<OccupancyTracker::Segment>&& history) {
- Mutex::Autolock lock(getBE().mBufferingStatsMutex);
- auto& stats = getBE().mBufferingStats[layerName];
- for (const auto& segment : history) {
- if (!segment.usedThirdBuffer) {
- stats.twoBufferTime += segment.totalTime;
- }
- if (segment.occupancyAverage < 1.0f) {
- stats.doubleBufferedTime += segment.totalTime;
- } else if (segment.occupancyAverage < 2.0f) {
- stats.tripleBufferedTime += segment.totalTime;
- }
- ++stats.numSegments;
- stats.totalTime += segment.totalTime;
- }
-}
-
void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
result.append("Layer frame timestamps:\n");
// Traverse all layers to dump frame-events for each layer
@@ -4839,38 +4763,6 @@
[&] (Layer* layer) { layer->dumpFrameEvents(result); });
}
-void SurfaceFlinger::dumpBufferingStats(std::string& result) const {
- result.append("Buffering stats:\n");
- result.append(" [Layer name] <Active time> <Two buffer> "
- "<Double buffered> <Triple buffered>\n");
- Mutex::Autolock lock(getBE().mBufferingStatsMutex);
- typedef std::tuple<std::string, float, float, float> BufferTuple;
- std::map<float, BufferTuple, std::greater<float>> sorted;
- for (const auto& statsPair : getBE().mBufferingStats) {
- const char* name = statsPair.first.c_str();
- const SurfaceFlingerBE::BufferingStats& stats = statsPair.second;
- if (stats.numSegments == 0) {
- continue;
- }
- float activeTime = ns2ms(stats.totalTime) / 1000.0f;
- float twoBufferRatio = static_cast<float>(stats.twoBufferTime) /
- stats.totalTime;
- float doubleBufferRatio = static_cast<float>(
- stats.doubleBufferedTime) / stats.totalTime;
- float tripleBufferRatio = static_cast<float>(
- stats.tripleBufferedTime) / stats.totalTime;
- sorted.insert({activeTime, {name, twoBufferRatio,
- doubleBufferRatio, tripleBufferRatio}});
- }
- for (const auto& sortedPair : sorted) {
- float activeTime = sortedPair.first;
- const BufferTuple& values = sortedPair.second;
- StringAppendF(&result, " [%s] %.2f %.3f %.3f %.3f\n", std::get<0>(values).c_str(),
- activeTime, std::get<1>(values), std::get<2>(values), std::get<3>(values));
- }
- result.append("\n");
-}
-
void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
for (const auto& [token, display] : mDisplays) {
const auto displayId = PhysicalDisplayId::tryCast(display->getId());
@@ -5062,8 +4954,6 @@
StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load());
StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load());
- dumpBufferingStats(result);
-
/*
* Dump the visible layer list
*/
@@ -5430,8 +5320,8 @@
}
scheduleRepaint();
return NO_ERROR;
- case 1004: // Force refresh ahead of next VSYNC.
- scheduleRefresh(FrameHint::kActive);
+ case 1004: // Force composite ahead of next VSYNC.
+ scheduleComposite(FrameHint::kActive);
return NO_ERROR;
case 1005: { // Force commit ahead of next VSYNC.
Mutex::Autolock lock(mStateLock);
@@ -5439,8 +5329,8 @@
eTraversalNeeded);
return NO_ERROR;
}
- case 1006: // Force refresh immediately.
- signalRefresh();
+ case 1006: // Force composite immediately.
+ mEventQueue->scheduleComposite();
return NO_ERROR;
case 1007: // Unused.
return NAME_NOT_FOUND;
@@ -5510,15 +5400,12 @@
mClientColorMatrix = mat4();
}
- // TODO(b/193487656): Restore once HWASan bug is fixed.
-#if 0
// Check that supplied matrix's last row is {0,0,0,1} so we can avoid
// the division by w in the fragment shader
float4 lastRow(transpose(mClientColorMatrix)[3]);
if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) {
ALOGE("The color transform's last row must be (0, 0, 0, 1)");
}
-#endif
updateColorMatrixLocked();
return NO_ERROR;
@@ -5834,7 +5721,7 @@
const bool timerExpired = mKernelIdleTimerEnabled && expired;
if (display->onKernelTimerChanged(desiredModeId, timerExpired)) {
- mEventQueue->invalidate();
+ mEventQueue->scheduleCommit();
}
}));
}
@@ -6029,9 +5916,10 @@
traverseLayersInLayerStack(layerStack, args.uid, visitor);
};
- return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
- args.pixelFormat, args.allowProtected, args.grayscale,
- captureListener);
+ auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
+ reqSize, args.pixelFormat, args.allowProtected,
+ args.grayscale, captureListener);
+ return captureResultFuture.get().status;
}
status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
@@ -6066,9 +5954,15 @@
traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
};
- return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
- ui::PixelFormat::RGBA_8888, false /* allowProtected */,
- false /* grayscale */, captureListener);
+ if (captureListener == nullptr) {
+ ALOGE("capture screen must provide a capture listener callback");
+ return BAD_VALUE;
+ }
+ auto captureResultFuture =
+ captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
+ ui::PixelFormat::RGBA_8888, false /* allowProtected */,
+ false /* grayscale */, captureListener);
+ return captureResultFuture.get().status;
}
status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -6195,23 +6089,28 @@
});
};
- return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
- args.pixelFormat, args.allowProtected, args.grayscale,
- captureListener);
+ if (captureListener == nullptr) {
+ ALOGE("capture screen must provide a capture listener callback");
+ return BAD_VALUE;
+ }
+
+ auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
+ reqSize, args.pixelFormat, args.allowProtected,
+ args.grayscale, captureListener);
+ return captureResultFuture.get().status;
}
-status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
- TraverseLayersFunction traverseLayers,
- ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
- bool allowProtected, bool grayscale,
- const sp<IScreenCaptureListener>& captureListener) {
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+ RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
+ ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) {
ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
") that exceeds render target size limit.",
bufferSize.getWidth(), bufferSize.getHeight());
- return BAD_VALUE;
+ return ftl::yield<renderengine::RenderEngineResult>({BAD_VALUE, base::unique_fd()}).share();
}
// Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -6251,50 +6150,65 @@
false /* regionSampling */, grayscale, captureListener);
}
-status_t SurfaceFlinger::captureScreenCommon(
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
- if (captureListener == nullptr) {
- ALOGE("capture screen must provide a capture listener callback");
- return BAD_VALUE;
- }
-
bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
- static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
- if (mRefreshPending) {
- ALOGW("Skipping screenshot for now");
- captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling,
- grayscale, captureListener);
- return;
- }
+ auto scheduleResultFuture = schedule([=,
+ renderAreaFuture = std::move(renderAreaFuture)]() mutable
+ -> std::shared_future<renderengine::RenderEngineResult> {
ScreenCaptureResults captureResults;
std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
if (!renderArea) {
ALOGW("Skipping screen capture because of invalid render area.");
captureResults.result = NO_MEMORY;
captureListener->onScreenCaptureCompleted(captureResults);
- return;
+ return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})
+ .share();
}
- status_t result = NO_ERROR;
+ std::shared_future<renderengine::RenderEngineResult> renderEngineResultFuture;
+
renderArea->render([&] {
- result = renderScreenImplLocked(*renderArea, traverseLayers, buffer,
- canCaptureBlackoutContent, regionSampling, grayscale,
- captureResults);
+ renderEngineResultFuture =
+ renderScreenImplLocked(*renderArea, traverseLayers, buffer,
+ canCaptureBlackoutContent, regionSampling, grayscale,
+ captureResults);
});
+ // spring up a thread to unblock SF main thread and wait for
+ // RenderEngineResult to be available
+ if (captureListener != nullptr) {
+ std::async([=]() mutable {
+ ATRACE_NAME("captureListener is nonnull!");
+ auto& [status, drawFence] = renderEngineResultFuture.get();
+ captureResults.result = status;
+ captureResults.fence = new Fence(dup(drawFence));
+ captureListener->onScreenCaptureCompleted(captureResults);
+ });
+ }
+ return renderEngineResultFuture;
+ });
- captureResults.result = result;
- captureListener->onScreenCaptureCompleted(captureResults);
- }));
-
- return NO_ERROR;
+ // flatten scheduleResultFuture object to single shared_future object
+ if (captureListener == nullptr) {
+ std::future<renderengine::RenderEngineResult> captureScreenResultFuture =
+ ftl::chain(std::move(scheduleResultFuture))
+ .then([=](std::shared_future<renderengine::RenderEngineResult> futureObject)
+ -> renderengine::RenderEngineResult {
+ auto& [status, drawFence] = futureObject.get();
+ return {status, base::unique_fd(dup(drawFence))};
+ });
+ return captureScreenResultFuture.share();
+ } else {
+ return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}).share();
+ }
}
-status_t SurfaceFlinger::renderScreenImplLocked(
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScreenImplLocked(
const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer,
bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
@@ -6313,7 +6227,8 @@
// the impetus on WindowManager to not persist them.
if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
ALOGW("FB is protected: PERMISSION_DENIED");
- return PERMISSION_DENIED;
+ return ftl::yield<renderengine::RenderEngineResult>({PERMISSION_DENIED, base::unique_fd()})
+ .share();
}
captureResults.buffer = buffer->getBuffer();
@@ -6395,11 +6310,12 @@
});
- std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers(
- clientCompositionLayers.size());
+ std::vector<renderengine::LayerSettings> clientRenderEngineLayers;
+ clientRenderEngineLayers.reserve(clientCompositionLayers.size());
std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
- clientCompositionLayerPointers.begin(),
- std::pointer_traits<renderengine::LayerSettings*>::pointer_to);
+ std::back_inserter(clientRenderEngineLayers),
+ [](compositionengine::LayerFE::LayerSettings& settings)
+ -> renderengine::LayerSettings { return settings; });
// Use an empty fence for the buffer fence, since we just created the buffer so
// there is no need for synchronization with the GPU.
@@ -6407,24 +6323,22 @@
getRenderEngine().useProtectedContext(useProtected);
const constexpr bool kUseFramebufferCache = false;
- auto [status, drawFence] =
- getRenderEngine()
- .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
- kUseFramebufferCache, std::move(bufferFence))
- .get();
+ std::future<renderengine::RenderEngineResult> drawLayersResult =
+ getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer,
+ kUseFramebufferCache, std::move(bufferFence));
- if (drawFence >= 0) {
- sp<Fence> releaseFence = new Fence(dup(drawFence));
- for (auto* layer : renderedLayers) {
- layer->onLayerDisplayed(releaseFence);
- }
+ std::shared_future<renderengine::RenderEngineResult> drawLayersResultFuture =
+ drawLayersResult.share(); // drawLayersResult will be moved to shared one
+
+ for (auto* layer : renderedLayers) {
+ // make a copy of shared_future object for each layer
+ layer->onLayerDisplayed(drawLayersResultFuture);
}
- captureResults.fence = new Fence(drawFence.release());
// Always switch back to unprotected context.
getRenderEngine().useProtectedContext(false);
- return status;
+ return drawLayersResultFuture;
}
void SurfaceFlinger::windowInfosReported() {
@@ -6552,8 +6466,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);
@@ -6617,6 +6533,10 @@
}
}
+void SurfaceFlinger::onLayerUpdate() {
+ scheduleCommit(FrameHint::kActive);
+}
+
// WARNING: ONLY CALL THIS FROM LAYER DTOR
// Here we add children in the current state to offscreen layers and remove the
// layer itself from the offscreen layer list. Since
@@ -6681,7 +6601,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);
@@ -6815,7 +6735,7 @@
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
- Fps maxRefreshRate(60.f);
+ Fps maxRefreshRate = 60_Hz;
if (!getHwComposer().isHeadless()) {
if (const auto display = getDefaultDisplayDevice()) {
@@ -6828,7 +6748,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;
@@ -6847,7 +6767,7 @@
return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
}
-void SurfaceFlinger::TransactionState::traverseStatesWithBuffers(
+void TransactionState::traverseStatesWithBuffers(
std::function<void(const layer_state_t&)> visitor) {
for (const auto& state : states) {
if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && state.state.surface) {
@@ -6857,7 +6777,7 @@
}
void SurfaceFlinger::setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
- const wp<IBinder>& parent, const wp<Layer> parentLayer,
+ const sp<IBinder>& parent, const wp<Layer> parentLayer,
const wp<IBinder>& producer, bool addToRoot) {
Mutex::Autolock lock(mCreatedLayersLock);
mCreatedLayers[handle->localBinder()] =
@@ -6901,9 +6821,9 @@
sp<Layer> parent;
bool allowAddRoot = state->addToRoot;
if (state->initialParent != nullptr) {
- parent = fromHandle(state->initialParent.promote()).promote();
+ parent = fromHandle(state->initialParent).promote();
if (parent == nullptr) {
- ALOGE("Invalid parent %p", state->initialParent.unsafe_get());
+ ALOGE("Invalid parent %p", state->initialParent.get());
allowAddRoot = false;
}
} else if (state->initialParentLayer != nullptr) {
@@ -6938,19 +6858,16 @@
}
}
+ mInterceptor->saveSurfaceCreation(layer);
return layer;
}
-void SurfaceFlinger::scheduleRegionSamplingThread() {
- static_cast<void>(schedule([&] { notifyRegionSamplingThread(); }));
-}
-
-void SurfaceFlinger::notifyRegionSamplingThread() {
+void SurfaceFlinger::sample() {
if (!mLumaSampling || !mRegionSamplingThread) {
return;
}
- mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate());
+ mRegionSamplingThread->onCompositionComplete(mEventQueue->getScheduledFrameTime());
}
void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1217d63..276c7f6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -32,7 +32,6 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
-#include <gui/OccupancyTracker.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/mat4.h>
#include <renderengine/LayerSettings.h>
@@ -57,6 +56,7 @@
#include "Fps.h"
#include "FrameTracker.h"
#include "LayerVector.h"
+#include "Scheduler/MessageQueue.h"
#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
#include "Scheduler/Scheduler.h"
@@ -65,6 +65,7 @@
#include "SurfaceTracing.h"
#include "TracedOrdinal.h"
#include "TransactionCallbackInvoker.h"
+#include "TransactionState.h"
#include <atomic>
#include <cstdint>
@@ -155,28 +156,13 @@
nsecs_t mFrameBuckets[NUM_BUCKETS] = {};
nsecs_t mTotalTime = 0;
std::atomic<nsecs_t> mLastSwapTime = 0;
-
- // Double- vs. triple-buffering stats
- struct BufferingStats {
- size_t numSegments = 0;
- nsecs_t totalTime = 0;
-
- // "Two buffer" means that a third buffer was never used, whereas
- // "double-buffered" means that on average the segment only used two
- // buffers (though it may have used a third for some part of the
- // segment)
- nsecs_t twoBufferTime = 0;
- nsecs_t doubleBufferedTime = 0;
- nsecs_t tripleBufferedTime = 0;
- };
- mutable Mutex mBufferingStatsMutex;
- std::unordered_map<std::string, BufferingStats> mBufferingStats;
};
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
private IBinder::DeathRecipient,
private HWC2::ComposerCallback,
+ private ICompositor,
private ISchedulerCallback {
public:
struct SkipInitializationTag {};
@@ -287,11 +273,13 @@
[[nodiscard]] std::future<T> schedule(F&&);
// Schedule commit of transactions on the main thread ahead of the next VSYNC.
- void scheduleInvalidate(FrameHint);
- // As above, but also force refresh regardless if transactions were committed.
- void scheduleRefresh(FrameHint) override;
+ void scheduleCommit(FrameHint);
+ // As above, but also force composite regardless if transactions were committed.
+ void scheduleComposite(FrameHint) override;
// As above, but also force dirty geometry to repaint.
void scheduleRepaint();
+ // Schedule sampling independently from commit or composite.
+ void scheduleSample();
surfaceflinger::Factory& getFactory() { return mFactory; }
@@ -305,11 +293,6 @@
// utility function to delete a texture on the main thread
void deleteTextureAsync(uint32_t texture);
- // called on the main thread by MessageQueue when an internal message
- // is received
- // TODO: this should be made accessible only to MessageQueue
- void onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime);
-
renderengine::RenderEngine& getRenderEngine() const;
bool authenticateSurfaceTextureLocked(
@@ -317,6 +300,7 @@
void onLayerFirstRef(Layer*);
void onLayerDestroyed(Layer*);
+ void onLayerUpdate();
void removeHierarchyFromOffscreenLayers(Layer* layer);
void removeFromOffscreenLayers(Layer* layer);
@@ -347,13 +331,6 @@
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
- virtual uint32_t setClientStateLocked(
- const FrameTimelineInfo& info, const ComposerState& composerState,
- int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime,
- uint32_t permissions,
- std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
- REQUIRES(mStateLock);
-
virtual void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
REQUIRES(mStateLock);
@@ -478,96 +455,6 @@
hal::Connection connection = hal::Connection::INVALID;
};
- class CountDownLatch {
- public:
- enum {
- eSyncTransaction = 1 << 0,
- eSyncInputWindows = 1 << 1,
- };
- explicit CountDownLatch(uint32_t flags) : mFlags(flags) {}
-
- // True if there is no waiting condition after count down.
- bool countDown(uint32_t flag) {
- std::unique_lock<std::mutex> lock(mMutex);
- if (mFlags == 0) {
- return true;
- }
- mFlags &= ~flag;
- if (mFlags == 0) {
- mCountDownComplete.notify_all();
- return true;
- }
- return false;
- }
-
- // Return true if triggered.
- bool wait_until(const std::chrono::seconds& timeout) const {
- std::unique_lock<std::mutex> lock(mMutex);
- const auto untilTime = std::chrono::system_clock::now() + timeout;
- while (mFlags != 0) {
- // Conditional variables can be woken up sporadically, so we check count
- // to verify the wakeup was triggered by |countDown|.
- if (std::cv_status::timeout == mCountDownComplete.wait_until(lock, untilTime)) {
- return false;
- }
- }
- return true;
- }
-
- private:
- uint32_t mFlags;
- mutable std::condition_variable mCountDownComplete;
- mutable std::mutex mMutex;
- };
-
- struct TransactionState {
- TransactionState(const FrameTimelineInfo& frameTimelineInfo,
- const Vector<ComposerState>& composerStates,
- const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
- const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
- bool isAutoTimestamp, const client_cache_t& uncacheBuffer,
- int64_t postTime, uint32_t permissions, bool hasListenerCallbacks,
- std::vector<ListenerCallbacks> listenerCallbacks, int originPid,
- int originUid, uint64_t transactionId)
- : frameTimelineInfo(frameTimelineInfo),
- states(composerStates),
- displays(displayStates),
- flags(transactionFlags),
- applyToken(applyToken),
- inputWindowCommands(inputWindowCommands),
- desiredPresentTime(desiredPresentTime),
- isAutoTimestamp(isAutoTimestamp),
- buffer(uncacheBuffer),
- postTime(postTime),
- permissions(permissions),
- hasListenerCallbacks(hasListenerCallbacks),
- listenerCallbacks(listenerCallbacks),
- originPid(originPid),
- originUid(originUid),
- id(transactionId) {}
-
- void traverseStatesWithBuffers(std::function<void(const layer_state_t&)> visitor);
-
- FrameTimelineInfo frameTimelineInfo;
- Vector<ComposerState> states;
- Vector<DisplayState> displays;
- uint32_t flags;
- sp<IBinder> applyToken;
- InputWindowCommands inputWindowCommands;
- const int64_t desiredPresentTime;
- const bool isAutoTimestamp;
- client_cache_t buffer;
- const int64_t postTime;
- uint32_t permissions;
- bool hasListenerCallbacks;
- std::vector<ListenerCallbacks> listenerCallbacks;
- int originPid;
- int originUid;
- uint64_t id;
- std::shared_ptr<CountDownLatch> transactionCommittedSignal;
- };
-
template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr>
static Dumper dumper(F&& dump) {
using namespace std::placeholders;
@@ -734,9 +621,6 @@
// Implements IBinder::DeathRecipient.
void binderDied(const wp<IBinder>& who) override;
- // Implements RefBase.
- void onFirstRef() override;
-
// HWC2::ComposerCallback overrides:
void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp,
std::optional<hal::VsyncPeriodNanos>) override;
@@ -746,6 +630,19 @@
const hal::VsyncPeriodChangeTimeline&) override;
void onComposerHalSeamlessPossible(hal::HWDisplayId) override;
+ // ICompositor overrides:
+
+ // Commits transactions for layers and displays. Returns whether any state has been invalidated,
+ // i.e. whether a frame should be composited for each display.
+ bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) override;
+
+ // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
+ // via RenderEngine and the Composer HAL, respectively.
+ void composite(nsecs_t frameTime) override;
+
+ // Samples the composited frame via RegionSamplingThread.
+ void sample() override;
+
/*
* ISchedulerCallback
*/
@@ -766,13 +663,6 @@
// Show spinner with refresh rate overlay
bool mRefreshRateOverlaySpinner = false;
- /*
- * Message handling
- */
- // Can only be called from the main thread or with mStateLock held
- void signalLayerUpdate();
- void signalRefresh();
-
// Called on the main thread in response to initializeDisplays()
void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode.
@@ -797,10 +687,6 @@
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
EXCLUDES(mStateLock);
- // Handle the INVALIDATE message queue event, latching new buffers and applying
- // incoming transactions
- void onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime);
-
// Returns whether transactions were committed.
bool flushAndCommitTransactions() EXCLUDES(mStateLock);
@@ -808,12 +694,10 @@
void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
void doCommitTransactions() REQUIRES(mStateLock);
- // Handle the REFRESH message queue event, sending the current frame down to RenderEngine and
- // the Composer HAL for presentation
- void onMessageRefresh();
+ // Returns whether a new buffer has been latched.
+ bool latchBuffers();
- // Returns whether a new buffer has been latched (see handlePageFlip())
- bool handleMessageInvalidate();
+ void updateLayerGeometry();
void updateInputFlinger();
void notifyWindowInfos();
@@ -824,16 +708,11 @@
void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock);
void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod);
- /* handlePageFlip - latch a new buffer if available and compute the dirty
- * region. Returns whether a new buffer has been latched, i.e., whether it
- * is necessary to perform a refresh during this vsync.
- */
- bool handlePageFlip();
/*
* Transactions
*/
- void applyTransactionState(const FrameTimelineInfo& info, const Vector<ComposerState>& state,
+ bool applyTransactionState(const FrameTimelineInfo& info, const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -843,10 +722,14 @@
int originPid, int originUid, uint64_t transactionId)
REQUIRES(mStateLock);
// flush pending transaction that was presented after desiredPresentTime.
- void flushTransactionQueues();
+ bool flushTransactionQueues();
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
+ uint32_t setClientStateLocked(const FrameTimelineInfo&, const ComposerState&,
+ int64_t desiredPresentTime, bool isAutoTimestamp,
+ int64_t postTime, uint32_t permissions) REQUIRES(mStateLock);
+
uint32_t getTransactionFlags() const;
// Sets the masked bits, and returns the old flags.
@@ -903,8 +786,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.
@@ -923,17 +804,17 @@
// Boot animation, on/off animations and screen capture
void startBootAnim();
- status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
- ui::PixelFormat, bool allowProtected, bool grayscale,
- const sp<IScreenCaptureListener>&);
- status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction,
- const std::shared_ptr<renderengine::ExternalTexture>&,
- bool regionSampling, bool grayscale,
- const sp<IScreenCaptureListener>&);
- status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
- const std::shared_ptr<renderengine::ExternalTexture>&,
- bool canCaptureBlackoutContent, bool regionSampling,
- bool grayscale, ScreenCaptureResults&);
+ std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
+ RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat,
+ bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>&);
+ std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
+ RenderAreaFuture, TraverseLayersFunction,
+ const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
+ bool grayscale, const sp<IScreenCaptureListener>&);
+ std::shared_future<renderengine::RenderEngineResult> renderScreenImplLocked(
+ const RenderArea&, TraverseLayersFunction,
+ const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
+ bool regionSampling, bool grayscale, ScreenCaptureResults&);
// If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a
// matching ownerUid
@@ -1066,6 +947,11 @@
*/
nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
+ void setHWCVsyncEnabled(PhysicalDisplayId id, hal::Vsync enabled) {
+ mLastHWCVsyncState = enabled;
+ 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);
@@ -1158,10 +1044,6 @@
void dumpStaticScreenStats(std::string& result) const;
// Not const because each Layer needs to query Fences and cache timestamps.
void dumpFrameEventsLocked(std::string& result);
-
- void recordBufferingStats(const std::string& layerName,
- std::vector<OccupancyTracker::Segment>&& history);
- void dumpBufferingStats(std::string& result) const;
void dumpDisplayIdentificationData(std::string& result) const REQUIRES(mStateLock);
void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
@@ -1229,7 +1111,6 @@
std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
bool mAnimTransactionPending = false;
SortedVector<sp<Layer>> mLayersPendingRemoval;
- bool mForceTraversal = false;
// global color transform states
Daltonizer mDaltonizer;
@@ -1250,7 +1131,7 @@
bool mLayersRemoved = false;
bool mLayersAdded = false;
- std::atomic_bool mForceRefresh = false;
+ std::atomic_bool mMustComposite = false;
std::atomic_bool mGeometryDirty = false;
// constant members (no synchronization needed for access)
@@ -1350,10 +1231,6 @@
mutable Mutex mDestroyedLayerLock;
Vector<Layer const *> mDestroyedLayers;
- nsecs_t mRefreshStartTime = 0;
-
- std::atomic<bool> mRefreshPending = false;
-
// We maintain a pool of pre-generated texture names to hand out to avoid
// layer creation needing to run on the main thread (which it would
// otherwise need to do to access RenderEngine).
@@ -1427,6 +1304,7 @@
std::atomic<nsecs_t> mExpectedPresentTime = 0;
nsecs_t mScheduledPresentTime = 0;
hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
+ hal::Vsync mLastHWCVsyncState = hal::Vsync::DISABLE;
// below flags are set by main thread only
bool mSetActiveModePending = false;
@@ -1446,9 +1324,6 @@
Hwc2::impl::PowerAdvisor mPowerAdvisor;
- // This should only be accessed on the main thread.
- nsecs_t mFrameStartTime = 0;
-
void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock);
// Flag used to set override desired display mode from backdoor
@@ -1470,7 +1345,7 @@
GUARDED_BY(mStateLock);
mutable Mutex mCreatedLayersLock;
struct LayerCreatedState {
- LayerCreatedState(const wp<Layer>& layer, const wp<IBinder>& parent,
+ LayerCreatedState(const wp<Layer>& layer, const sp<IBinder>& parent,
const wp<Layer> parentLayer, const wp<IBinder>& producer, bool addToRoot)
: layer(layer),
initialParent(parent),
@@ -1480,7 +1355,7 @@
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;
+ sp<IBinder> initialParent;
wp<Layer> initialParentLayer;
// Indicates the initial graphic buffer producer of the created layer, only used for
// creating layer in SurfaceFlinger.
@@ -1495,16 +1370,13 @@
// 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 sp<IBinder>& parent, const wp<Layer> parentLayer,
const wp<IBinder>& producer, bool addToRoot);
auto getLayerCreatedState(const sp<IBinder>& handle);
sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
- void scheduleRegionSamplingThread();
- void notifyRegionSamplingThread();
-
bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) {
return std::any_of(mDisplays.begin(), mDisplays.end(),
[](std::pair<wp<IBinder>, sp<DisplayDevice>> display) {
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 89d1c4d..9a2f910 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -51,8 +51,8 @@
return std::make_unique<android::impl::HWComposer>(serviceName);
}
-std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue() {
- return std::make_unique<android::impl::MessageQueue>();
+std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue(ICompositor& compositor) {
+ return std::make_unique<android::impl::MessageQueue>(compositor);
}
std::unique_ptr<scheduler::VsyncConfiguration> DefaultFactory::createVsyncConfiguration(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index b8bf2ba..2be09ee 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -27,7 +27,7 @@
virtual ~DefaultFactory();
std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
- std::unique_ptr<MessageQueue> createMessageQueue() override;
+ std::unique_ptr<MessageQueue> createMessageQueue(ICompositor&) override;
std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) override;
std::unique_ptr<Scheduler> createScheduler(
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 13c95dd..bca533b 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -31,11 +31,11 @@
typedef int32_t PixelFormat;
class BufferQueueLayer;
-class BufferStateLayer;
class BufferLayerConsumer;
-class EffectLayer;
+class BufferStateLayer;
class ContainerLayer;
class DisplayDevice;
+class EffectLayer;
class FrameTracer;
class GraphicBuffer;
class HWComposer;
@@ -50,6 +50,7 @@
class TimeStats;
struct DisplayDeviceCreationArgs;
+struct ICompositor;
struct ISchedulerCallback;
struct LayerCreationArgs;
@@ -76,7 +77,7 @@
class Factory {
public:
virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
- virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
+ virtual std::unique_ptr<MessageQueue> createMessageQueue(ICompositor&) = 0;
virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) = 0;
virtual std::unique_ptr<Scheduler> createScheduler(
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 7c1f21f..bf2038b 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -564,7 +564,7 @@
layerRecords += record.second.stats.size();
}
- return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
+ return layerRecords < MAX_NUM_LAYER_STATS;
}
void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
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/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
new file mode 100644
index 0000000..fb1d43b
--- /dev/null
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -0,0 +1,461 @@
+/*
+ * 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.
+ */
+
+#include <gui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+
+#include "LayerProtoHelper.h"
+#include "TransactionProtoParser.h"
+
+namespace android::surfaceflinger {
+
+proto::TransactionState TransactionProtoParser::toProto(
+ const TransactionState& t, std::function<int32_t(const sp<IBinder>&)> getLayerId,
+ std::function<int32_t(const sp<IBinder>&)> getDisplayId) {
+ proto::TransactionState proto;
+ proto.set_pid(t.originPid);
+ proto.set_uid(t.originUid);
+ proto.set_vsync_id(t.frameTimelineInfo.vsyncId);
+ proto.set_input_event_id(t.frameTimelineInfo.inputEventId);
+ proto.set_post_time(t.postTime);
+
+ for (auto& layerState : t.states) {
+ proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state, getLayerId)));
+ }
+
+ for (auto& displayState : t.displays) {
+ proto.mutable_display_changes()->Add(std::move(toProto(displayState, getDisplayId)));
+ }
+ return proto;
+}
+
+proto::LayerState TransactionProtoParser::toProto(
+ const layer_state_t& layer, std::function<int32_t(const sp<IBinder>&)> getLayerId) {
+ proto::LayerState proto;
+ proto.set_layer_id(layer.layerId);
+ proto.set_what(layer.what);
+
+ if (layer.what & layer_state_t::ePositionChanged) {
+ proto.set_x(layer.x);
+ proto.set_y(layer.y);
+ }
+ if (layer.what & layer_state_t::eLayerChanged) {
+ proto.set_z(layer.z);
+ }
+ if (layer.what & layer_state_t::eSizeChanged) {
+ proto.set_w(layer.w);
+ proto.set_h(layer.h);
+ }
+ if (layer.what & layer_state_t::eLayerStackChanged) {
+ proto.set_layer_stack(layer.layerStack.id);
+ }
+ if (layer.what & layer_state_t::eFlagsChanged) {
+ proto.set_flags(layer.flags);
+ proto.set_mask(layer.mask);
+ }
+ if (layer.what & layer_state_t::eMatrixChanged) {
+ proto::LayerState_Matrix22* matrixProto = proto.mutable_matrix();
+ matrixProto->set_dsdx(layer.matrix.dsdx);
+ matrixProto->set_dsdy(layer.matrix.dsdy);
+ matrixProto->set_dtdx(layer.matrix.dtdx);
+ matrixProto->set_dtdy(layer.matrix.dtdy);
+ }
+ if (layer.what & layer_state_t::eCornerRadiusChanged) {
+ proto.set_corner_radius(layer.cornerRadius);
+ }
+ if (layer.what & layer_state_t::eBackgroundBlurRadiusChanged) {
+ proto.set_background_blur_radius(layer.backgroundBlurRadius);
+ }
+
+ if (layer.what & layer_state_t::eAlphaChanged) {
+ proto.set_alpha(layer.alpha);
+ }
+
+ if (layer.what & layer_state_t::eColorChanged) {
+ proto::LayerState_Color3* colorProto = proto.mutable_color();
+ colorProto->set_r(layer.color.r);
+ colorProto->set_g(layer.color.g);
+ colorProto->set_b(layer.color.b);
+ }
+ if (layer.what & layer_state_t::eTransparentRegionChanged) {
+ LayerProtoHelper::writeToProto(layer.transparentRegion, proto.mutable_transparent_region());
+ }
+ if (layer.what & layer_state_t::eTransformChanged) {
+ proto.set_transform(layer.transform);
+ }
+ if (layer.what & layer_state_t::eTransformToDisplayInverseChanged) {
+ proto.set_transform_to_display_inverse(layer.transformToDisplayInverse);
+ }
+ if (layer.what & layer_state_t::eCropChanged) {
+ LayerProtoHelper::writeToProto(layer.crop, proto.mutable_crop());
+ }
+ if (layer.what & layer_state_t::eBufferChanged) {
+ proto::LayerState_BufferData* bufferProto = proto.mutable_buffer_data();
+ if (layer.bufferData.buffer) {
+ bufferProto->set_buffer_id(layer.bufferData.buffer->getId());
+ bufferProto->set_width(layer.bufferData.buffer->getWidth());
+ bufferProto->set_height(layer.bufferData.buffer->getHeight());
+ }
+ bufferProto->set_frame_number(layer.bufferData.frameNumber);
+ bufferProto->set_flags(layer.bufferData.flags.get());
+ bufferProto->set_cached_buffer_id(layer.bufferData.cachedBuffer.id);
+ }
+ if (layer.what & layer_state_t::eSidebandStreamChanged) {
+ proto.set_has_sideband_stream(layer.sidebandStream != nullptr);
+ }
+
+ if (layer.what & layer_state_t::eApiChanged) {
+ proto.set_api(layer.api);
+ }
+
+ if (layer.what & layer_state_t::eColorTransformChanged) {
+ LayerProtoHelper::writeToProto(layer.colorTransform, proto.mutable_color_transform());
+ }
+ if (layer.what & layer_state_t::eBlurRegionsChanged) {
+ for (auto& region : layer.blurRegions) {
+ LayerProtoHelper::writeToProto(region, proto.add_blur_regions());
+ }
+ }
+
+ if (layer.what & layer_state_t::eReparent) {
+ int32_t layerId = layer.parentSurfaceControlForChild
+ ? getLayerId(layer.parentSurfaceControlForChild->getHandle())
+ : -1;
+ proto.set_parent_id(layerId);
+ }
+ if (layer.what & layer_state_t::eRelativeLayerChanged) {
+ int32_t layerId = layer.relativeLayerSurfaceControl
+ ? getLayerId(layer.relativeLayerSurfaceControl->getHandle())
+ : -1;
+ proto.set_relative_parent_id(layerId);
+ }
+
+ if (layer.what & layer_state_t::eInputInfoChanged) {
+ if (layer.windowInfoHandle) {
+ const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo();
+ proto::LayerState_WindowInfo* windowInfoProto = proto.mutable_window_info_handle();
+ windowInfoProto->set_layout_params_flags(inputInfo->flags.get());
+ windowInfoProto->set_layout_params_type(static_cast<int32_t>(inputInfo->type));
+ LayerProtoHelper::writeToProto(inputInfo->touchableRegion,
+ windowInfoProto->mutable_touchable_region());
+ windowInfoProto->set_surface_inset(inputInfo->surfaceInset);
+ windowInfoProto->set_focusable(inputInfo->focusable);
+ windowInfoProto->set_has_wallpaper(inputInfo->hasWallpaper);
+ windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
+ proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform();
+ transformProto->set_dsdx(inputInfo->transform.dsdx());
+ transformProto->set_dtdx(inputInfo->transform.dtdx());
+ transformProto->set_dtdy(inputInfo->transform.dtdy());
+ transformProto->set_dsdy(inputInfo->transform.dsdy());
+ transformProto->set_tx(inputInfo->transform.tx());
+ transformProto->set_ty(inputInfo->transform.ty());
+ windowInfoProto->set_replace_touchable_region_with_crop(
+ inputInfo->replaceTouchableRegionWithCrop);
+ windowInfoProto->set_crop_layer_id(
+ getLayerId(inputInfo->touchableRegionCropHandle.promote()));
+ }
+ }
+ if (layer.what & layer_state_t::eBackgroundColorChanged) {
+ proto.set_bg_color_alpha(layer.bgColorAlpha);
+ proto.set_bg_color_dataspace(static_cast<int32_t>(layer.bgColorDataspace));
+ proto::LayerState_Color3* colorProto = proto.mutable_color();
+ colorProto->set_r(layer.color.r);
+ colorProto->set_g(layer.color.g);
+ colorProto->set_b(layer.color.b);
+ }
+ if (layer.what & layer_state_t::eColorSpaceAgnosticChanged) {
+ proto.set_color_space_agnostic(layer.colorSpaceAgnostic);
+ }
+ if (layer.what & layer_state_t::eShadowRadiusChanged) {
+ proto.set_shadow_radius(layer.shadowRadius);
+ }
+ if (layer.what & layer_state_t::eFrameRateSelectionPriority) {
+ proto.set_frame_rate_selection_priority(layer.frameRateSelectionPriority);
+ }
+ if (layer.what & layer_state_t::eFrameRateChanged) {
+ proto.set_frame_rate(layer.frameRate);
+ proto.set_frame_rate_compatibility(layer.frameRateCompatibility);
+ proto.set_change_frame_rate_strategy(layer.changeFrameRateStrategy);
+ }
+ if (layer.what & layer_state_t::eFixedTransformHintChanged) {
+ proto.set_fixed_transform_hint(layer.fixedTransformHint);
+ }
+ if (layer.what & layer_state_t::eAutoRefreshChanged) {
+ proto.set_auto_refresh(layer.autoRefresh);
+ }
+ if (layer.what & layer_state_t::eTrustedOverlayChanged) {
+ proto.set_is_trusted_overlay(layer.isTrustedOverlay);
+ }
+ if (layer.what & layer_state_t::eBufferCropChanged) {
+ LayerProtoHelper::writeToProto(layer.bufferCrop, proto.mutable_buffer_crop());
+ }
+ if (layer.what & layer_state_t::eDestinationFrameChanged) {
+ LayerProtoHelper::writeToProto(layer.destinationFrame, proto.mutable_destination_frame());
+ }
+ if (layer.what & layer_state_t::eDropInputModeChanged) {
+ proto.set_drop_input_mode(
+ static_cast<proto::LayerState_DropInputMode>(layer.dropInputMode));
+ }
+ return proto;
+}
+
+proto::DisplayState TransactionProtoParser::toProto(
+ const DisplayState& display, std::function<int32_t(const sp<IBinder>&)> getDisplayId) {
+ proto::DisplayState proto;
+ proto.set_what(display.what);
+ proto.set_id(getDisplayId(display.token));
+
+ if (display.what & DisplayState::eLayerStackChanged) {
+ proto.set_layer_stack(display.layerStack.id);
+ }
+ if (display.what & DisplayState::eDisplayProjectionChanged) {
+ proto.set_orientation(static_cast<uint32_t>(display.orientation));
+ LayerProtoHelper::writeToProto(display.orientedDisplaySpaceRect,
+ proto.mutable_oriented_display_space_rect());
+ LayerProtoHelper::writeToProto(display.layerStackSpaceRect,
+ proto.mutable_layer_stack_space_rect());
+ }
+ if (display.what & DisplayState::eDisplaySizeChanged) {
+ proto.set_width(display.width);
+ proto.set_height(display.height);
+ }
+ if (display.what & DisplayState::eFlagsChanged) {
+ proto.set_flags(display.flags);
+ }
+ return proto;
+}
+
+TransactionState TransactionProtoParser::fromProto(
+ const proto::TransactionState& proto, std::function<sp<IBinder>(int32_t)> getLayerHandle,
+ std::function<sp<IBinder>(int32_t)> getDisplayHandle) {
+ TransactionState t;
+ t.originPid = proto.pid();
+ t.originUid = proto.uid();
+ t.frameTimelineInfo.vsyncId = proto.vsync_id();
+ t.frameTimelineInfo.inputEventId = proto.input_event_id();
+ t.postTime = proto.post_time();
+ int32_t layerCount = proto.layer_changes_size();
+ t.states.reserve(static_cast<size_t>(layerCount));
+ for (int i = 0; i < layerCount; i++) {
+ ComposerState s;
+ s.state = std::move(fromProto(proto.layer_changes(i), getLayerHandle));
+ t.states.add(s);
+ }
+
+ int32_t displayCount = proto.display_changes_size();
+ t.displays.reserve(static_cast<size_t>(displayCount));
+ for (int i = 0; i < displayCount; i++) {
+ t.displays.add(fromProto(proto.display_changes(i), getDisplayHandle));
+ }
+ return t;
+}
+
+layer_state_t TransactionProtoParser::fromProto(
+ const proto::LayerState& proto, std::function<sp<IBinder>(int32_t)> getLayerHandle) {
+ layer_state_t layer;
+ layer.layerId = proto.layer_id();
+ layer.what = proto.what();
+
+ if (layer.what & layer_state_t::ePositionChanged) {
+ layer.x = proto.x();
+ layer.y = proto.y();
+ }
+ if (layer.what & layer_state_t::eLayerChanged) {
+ layer.z = proto.z();
+ }
+ if (layer.what & layer_state_t::eSizeChanged) {
+ layer.w = proto.w();
+ layer.h = proto.h();
+ }
+ if (layer.what & layer_state_t::eLayerStackChanged) {
+ layer.layerStack.id = proto.layer_stack();
+ }
+ if (layer.what & layer_state_t::eFlagsChanged) {
+ layer.flags = proto.flags();
+ layer.mask = proto.mask();
+ }
+ if (layer.what & layer_state_t::eMatrixChanged) {
+ const proto::LayerState_Matrix22& matrixProto = proto.matrix();
+ layer.matrix.dsdx = matrixProto.dsdx();
+ layer.matrix.dsdy = matrixProto.dsdy();
+ layer.matrix.dtdx = matrixProto.dtdx();
+ layer.matrix.dtdy = matrixProto.dtdy();
+ }
+ if (layer.what & layer_state_t::eCornerRadiusChanged) {
+ layer.cornerRadius = proto.corner_radius();
+ }
+ if (layer.what & layer_state_t::eBackgroundBlurRadiusChanged) {
+ layer.backgroundBlurRadius = proto.background_blur_radius();
+ }
+
+ if (layer.what & layer_state_t::eAlphaChanged) {
+ layer.alpha = proto.alpha();
+ }
+
+ if (layer.what & layer_state_t::eColorChanged) {
+ const proto::LayerState_Color3& colorProto = proto.color();
+ layer.color.r = colorProto.r();
+ layer.color.g = colorProto.g();
+ layer.color.b = colorProto.b();
+ }
+ if (layer.what & layer_state_t::eTransparentRegionChanged) {
+ LayerProtoHelper::readFromProto(proto.transparent_region(), layer.transparentRegion);
+ }
+ if (layer.what & layer_state_t::eTransformChanged) {
+ layer.transform = proto.transform();
+ }
+ if (layer.what & layer_state_t::eTransformToDisplayInverseChanged) {
+ layer.transformToDisplayInverse = proto.transform_to_display_inverse();
+ }
+ if (layer.what & layer_state_t::eCropChanged) {
+ LayerProtoHelper::readFromProto(proto.crop(), layer.crop);
+ }
+ if (layer.what & layer_state_t::eBufferChanged) {
+ const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
+ layer.bufferData.buffer = new GraphicBuffer(bufferProto.width(), bufferProto.height(),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+ layer.bufferData.frameNumber = bufferProto.frame_number();
+ layer.bufferData.flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
+ layer.bufferData.cachedBuffer.id = bufferProto.cached_buffer_id();
+ }
+ if (layer.what & layer_state_t::eSidebandStreamChanged) {
+ native_handle_t* handle = native_handle_create(0, 0);
+ layer.sidebandStream =
+ proto.has_sideband_stream() ? NativeHandle::create(handle, true) : nullptr;
+ }
+
+ if (layer.what & layer_state_t::eApiChanged) {
+ layer.api = proto.api();
+ }
+
+ if (layer.what & layer_state_t::eColorTransformChanged) {
+ LayerProtoHelper::readFromProto(proto.color_transform(), layer.colorTransform);
+ }
+ if (layer.what & layer_state_t::eBlurRegionsChanged) {
+ layer.blurRegions.reserve(static_cast<size_t>(proto.blur_regions_size()));
+ for (int i = 0; i < proto.blur_regions_size(); i++) {
+ android::BlurRegion region;
+ LayerProtoHelper::readFromProto(proto.blur_regions(i), region);
+ layer.blurRegions.push_back(region);
+ }
+ }
+
+ if (layer.what & layer_state_t::eReparent) {
+ int32_t layerId = proto.parent_id();
+ layer.parentSurfaceControlForChild =
+ new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
+ nullptr, layerId);
+ }
+ if (layer.what & layer_state_t::eRelativeLayerChanged) {
+ int32_t layerId = proto.relative_parent_id();
+ layer.relativeLayerSurfaceControl =
+ new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
+ nullptr, layerId);
+ }
+
+ if ((layer.what & layer_state_t::eInputInfoChanged) && proto.has_window_info_handle()) {
+ gui::WindowInfo inputInfo;
+ const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle();
+
+ inputInfo.flags = static_cast<gui::WindowInfo::Flag>(windowInfoProto.layout_params_flags());
+ inputInfo.type = static_cast<gui::WindowInfo::Type>(windowInfoProto.layout_params_type());
+ LayerProtoHelper::readFromProto(windowInfoProto.touchable_region(),
+ inputInfo.touchableRegion);
+ inputInfo.surfaceInset = windowInfoProto.surface_inset();
+ inputInfo.focusable = windowInfoProto.focusable();
+ inputInfo.hasWallpaper = windowInfoProto.has_wallpaper();
+ inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor();
+ const proto::LayerState_Transform& transformProto = windowInfoProto.transform();
+ inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(),
+ transformProto.dsdy());
+ inputInfo.transform.set(transformProto.tx(), transformProto.ty());
+ inputInfo.replaceTouchableRegionWithCrop =
+ windowInfoProto.replace_touchable_region_with_crop();
+ int32_t layerId = windowInfoProto.crop_layer_id();
+ inputInfo.touchableRegionCropHandle = getLayerHandle(layerId);
+ layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
+ }
+ if (layer.what & layer_state_t::eBackgroundColorChanged) {
+ layer.bgColorAlpha = proto.bg_color_alpha();
+ layer.bgColorDataspace = static_cast<ui::Dataspace>(proto.bg_color_dataspace());
+ const proto::LayerState_Color3& colorProto = proto.color();
+ layer.color.r = colorProto.r();
+ layer.color.g = colorProto.g();
+ layer.color.b = colorProto.b();
+ }
+ if (layer.what & layer_state_t::eColorSpaceAgnosticChanged) {
+ layer.colorSpaceAgnostic = proto.color_space_agnostic();
+ }
+ if (layer.what & layer_state_t::eShadowRadiusChanged) {
+ layer.shadowRadius = proto.shadow_radius();
+ }
+ if (layer.what & layer_state_t::eFrameRateSelectionPriority) {
+ layer.frameRateSelectionPriority = proto.frame_rate_selection_priority();
+ }
+ if (layer.what & layer_state_t::eFrameRateChanged) {
+ layer.frameRate = proto.frame_rate();
+ layer.frameRateCompatibility = static_cast<int8_t>(proto.frame_rate_compatibility());
+ layer.changeFrameRateStrategy = static_cast<int8_t>(proto.change_frame_rate_strategy());
+ }
+ if (layer.what & layer_state_t::eFixedTransformHintChanged) {
+ layer.fixedTransformHint =
+ static_cast<ui::Transform::RotationFlags>(proto.fixed_transform_hint());
+ }
+ if (layer.what & layer_state_t::eAutoRefreshChanged) {
+ layer.autoRefresh = proto.auto_refresh();
+ }
+ if (layer.what & layer_state_t::eTrustedOverlayChanged) {
+ layer.isTrustedOverlay = proto.is_trusted_overlay();
+ }
+ if (layer.what & layer_state_t::eBufferCropChanged) {
+ LayerProtoHelper::readFromProto(proto.buffer_crop(), layer.bufferCrop);
+ }
+ if (layer.what & layer_state_t::eDestinationFrameChanged) {
+ LayerProtoHelper::readFromProto(proto.destination_frame(), layer.destinationFrame);
+ }
+ if (layer.what & layer_state_t::eDropInputModeChanged) {
+ layer.dropInputMode = static_cast<gui::DropInputMode>(proto.drop_input_mode());
+ }
+ return layer;
+}
+
+DisplayState TransactionProtoParser::fromProto(
+ const proto::DisplayState& proto, std::function<sp<IBinder>(int32_t)> getDisplayHandle) {
+ DisplayState display;
+ display.what = proto.what();
+ display.token = getDisplayHandle(proto.id());
+
+ if (display.what & DisplayState::eLayerStackChanged) {
+ display.layerStack.id = proto.layer_stack();
+ }
+ if (display.what & DisplayState::eDisplayProjectionChanged) {
+ display.orientation = static_cast<ui::Rotation>(proto.orientation());
+ LayerProtoHelper::readFromProto(proto.oriented_display_space_rect(),
+ display.orientedDisplaySpaceRect);
+ LayerProtoHelper::readFromProto(proto.layer_stack_space_rect(),
+ display.layerStackSpaceRect);
+ }
+ if (display.what & DisplayState::eDisplaySizeChanged) {
+ display.width = proto.width();
+ display.height = proto.height();
+ }
+ if (display.what & DisplayState::eFlagsChanged) {
+ display.flags = proto.flags();
+ }
+ return display;
+}
+
+} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
new file mode 100644
index 0000000..a2b8889
--- /dev/null
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <layerproto/TransactionProto.h>
+#include <utils/RefBase.h>
+
+#include "TransactionState.h"
+
+namespace android::surfaceflinger {
+class TransactionProtoParser {
+public:
+ static proto::TransactionState toProto(
+ const TransactionState&, std::function<int32_t(const sp<IBinder>&)> getLayerIdFn,
+ std::function<int32_t(const sp<IBinder>&)> getDisplayIdFn);
+ static TransactionState fromProto(const proto::TransactionState&,
+ std::function<sp<IBinder>(int32_t)> getLayerHandleFn,
+ std::function<sp<IBinder>(int32_t)> getDisplayHandleFn);
+
+private:
+ static proto::LayerState toProto(const layer_state_t&,
+ std::function<int32_t(const sp<IBinder>&)> getLayerId);
+ static proto::DisplayState toProto(const DisplayState&,
+ std::function<int32_t(const sp<IBinder>&)> getDisplayId);
+ static layer_state_t fromProto(const proto::LayerState&,
+ std::function<sp<IBinder>(int32_t)> getLayerHandle);
+ static DisplayState fromProto(const proto::DisplayState&,
+ std::function<sp<IBinder>(int32_t)> getDisplayHandle);
+};
+
+} // namespace android::surfaceflinger
\ No newline at end of file
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 4b12a26..f3d46ea 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -49,6 +49,31 @@
return !callbacks.empty() && callbacks.front().type == CallbackId::Type::ON_COMMIT;
}
+TransactionCallbackInvoker::TransactionCallbackInvoker() {
+ mThread = std::thread([&]() {
+ std::unique_lock lock(mCallbackThreadMutex);
+
+ while (mKeepRunning) {
+ while (mCallbackThreadWork.size() > 0) {
+ mCallbackThreadWork.front()();
+ mCallbackThreadWork.pop();
+ }
+ mCallbackConditionVariable.wait(lock);
+ }
+ });
+}
+
+TransactionCallbackInvoker::~TransactionCallbackInvoker() {
+ {
+ std::unique_lock lock(mCallbackThreadMutex);
+ mKeepRunning = false;
+ mCallbackConditionVariable.notify_all();
+ }
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) {
auto& [listener, callbackIds] = listenerCallbacks;
auto& transactionStatsDeque = mCompletedTransactions[listener];
@@ -96,7 +121,7 @@
return addCallbackHandle(handle, std::vector<JankData>());
}
-status_t TransactionCallbackInvoker::findTransactionStats(
+status_t TransactionCallbackInvoker::findOrCreateTransactionStats(
const sp<IBinder>& listener, const std::vector<CallbackId>& callbackIds,
TransactionStats** outTransactionStats) {
auto& transactionStatsDeque = mCompletedTransactions[listener];
@@ -118,7 +143,8 @@
// If we can't find the transaction stats something has gone wrong. The client should call
// startRegistration before trying to add a callback handle.
TransactionStats* transactionStats;
- status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
+ status_t err =
+ findOrCreateTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
if (err != NO_ERROR) {
return err;
}
@@ -129,6 +155,38 @@
// destroyed the client side is dead and there won't be anyone to send the callback to.
sp<IBinder> surfaceControl = handle->surfaceControl.promote();
if (surfaceControl) {
+ sp<Fence> prevFence = nullptr;
+
+ for (const auto& futureStruct : handle->previousReleaseFences) {
+ sp<Fence> currentFence = sp<Fence>::make(dup(futureStruct.get().drawFence));
+ if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) {
+ prevFence = currentFence;
+ handle->previousReleaseFence = prevFence;
+ } else if (prevFence != nullptr) {
+ // If both fences are signaled or both are unsignaled, we need to merge
+ // them to get an accurate timestamp.
+ if (prevFence->getStatus() != Fence::Status::Invalid &&
+ prevFence->getStatus() == currentFence->getStatus()) {
+ char fenceName[32] = {};
+ snprintf(fenceName, 32, "%.28s", handle->name.c_str());
+ sp<Fence> mergedFence = Fence::merge(fenceName, prevFence, currentFence);
+ if (mergedFence->isValid()) {
+ handle->previousReleaseFence = mergedFence;
+ prevFence = handle->previousReleaseFence;
+ }
+ } else if (currentFence->getStatus() == Fence::Status::Unsignaled) {
+ // If one fence has signaled and the other hasn't, the unsignaled
+ // fence will approximately correspond with the correct timestamp.
+ // There's a small race if both fences signal at about the same time
+ // and their statuses are retrieved with unfortunate timing. However,
+ // by this point, they will have both signaled and only the timestamp
+ // will be slightly off; any dependencies after this point will
+ // already have been met.
+ handle->previousReleaseFence = currentFence;
+ }
+ }
+ }
+ handle->previousReleaseFences = {};
FrameEventHistoryStats eventStats(handle->frameNumber,
handle->gpuCompositionDoneFence->getSnapshot().fence,
handle->compositorTiming, handle->refreshStartTime,
@@ -147,7 +205,7 @@
mPresentFence = presentFence;
}
-void TransactionCallbackInvoker::sendCallbacks() {
+void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
// For each listener
auto completedTransactionsItr = mCompletedTransactions.begin();
while (completedTransactionsItr != mCompletedTransactions.end()) {
@@ -159,6 +217,10 @@
auto transactionStatsItr = transactionStatsDeque.begin();
while (transactionStatsItr != transactionStatsDeque.end()) {
auto& transactionStats = *transactionStatsItr;
+ if (onCommitOnly && !containsOnCommitCallbacks(transactionStats.callbackIds)) {
+ transactionStatsItr++;
+ continue;
+ }
// If the transaction has been latched
if (transactionStats.latchTime >= 0 &&
@@ -180,8 +242,15 @@
// keep it as an IBinder due to consistency reasons: if we
// interface_cast at the IPC boundary when reading a Parcel,
// we get pointers that compare unequal in the SF process.
- interface_cast<ITransactionCompletedListener>(listenerStats.listener)
- ->onTransactionCompleted(listenerStats);
+ {
+ std::unique_lock lock(mCallbackThreadMutex);
+ mCallbackThreadWork.push(
+ [stats = std::move(listenerStats)]() {
+ interface_cast<ITransactionCompletedListener>(stats.listener)
+ ->onTransactionCompleted(stats);
+ });
+ mCallbackConditionVariable.notify_all();
+ }
}
}
completedTransactionsItr++;
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 71ca6e5..e203d41 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -18,7 +18,9 @@
#include <condition_variable>
#include <deque>
+#include <future>
#include <mutex>
+#include <queue>
#include <thread>
#include <unordered_map>
#include <unordered_set>
@@ -27,6 +29,7 @@
#include <binder/IBinder.h>
#include <gui/ITransactionCompletedListener.h>
+#include <renderengine/RenderEngine.h>
#include <ui/Fence.h>
namespace android {
@@ -41,7 +44,9 @@
wp<IBinder> surfaceControl;
bool releasePreviousBuffer = false;
+ std::string name;
sp<Fence> previousReleaseFence;
+ std::vector<std::shared_future<renderengine::RenderEngineResult>> previousReleaseFences;
nsecs_t acquireTime = -1;
nsecs_t latchTime = -1;
uint32_t transformHint = 0;
@@ -56,8 +61,11 @@
class TransactionCallbackInvoker {
public:
+ TransactionCallbackInvoker();
+ ~TransactionCallbackInvoker();
+
status_t addCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
- const std::vector<JankData>& jankData);
+ const std::vector<JankData>& jankData);
status_t addOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
std::deque<sp<CallbackHandle>>& outRemainingHandles);
@@ -68,7 +76,7 @@
void addPresentFence(const sp<Fence>& presentFence);
- void sendCallbacks();
+ void sendCallbacks(bool onCommitOnly);
void clearCompletedTransactions() {
mCompletedTransactions.clear();
}
@@ -78,16 +86,20 @@
private:
- status_t findTransactionStats(const sp<IBinder>& listener,
- const std::vector<CallbackId>& callbackIds,
- TransactionStats** outTransactionStats);
-
-
+ status_t findOrCreateTransactionStats(const sp<IBinder>& listener,
+ const std::vector<CallbackId>& callbackIds,
+ TransactionStats** outTransactionStats);
std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash>
mCompletedTransactions;
sp<Fence> mPresentFence;
+
+ std::mutex mCallbackThreadMutex;
+ std::condition_variable mCallbackConditionVariable;
+ std::thread mThread;
+ bool mKeepRunning = true;
+ std::queue<std::function<void()>> mCallbackThreadWork;
};
} // namespace android
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
new file mode 100644
index 0000000..fe3f3fc
--- /dev/null
+++ b/services/surfaceflinger/TransactionState.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gui/LayerState.h>
+
+namespace android {
+class CountDownLatch;
+
+struct TransactionState {
+ TransactionState(const FrameTimelineInfo& frameTimelineInfo,
+ const Vector<ComposerState>& composerStates,
+ const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
+ const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime, bool isAutoTimestamp,
+ const client_cache_t& uncacheBuffer, int64_t postTime, uint32_t permissions,
+ bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks,
+ int originPid, int originUid, uint64_t transactionId)
+ : frameTimelineInfo(frameTimelineInfo),
+ states(composerStates),
+ displays(displayStates),
+ flags(transactionFlags),
+ applyToken(applyToken),
+ inputWindowCommands(inputWindowCommands),
+ desiredPresentTime(desiredPresentTime),
+ isAutoTimestamp(isAutoTimestamp),
+ buffer(uncacheBuffer),
+ postTime(postTime),
+ permissions(permissions),
+ hasListenerCallbacks(hasListenerCallbacks),
+ listenerCallbacks(listenerCallbacks),
+ originPid(originPid),
+ originUid(originUid),
+ id(transactionId) {}
+
+ TransactionState() {}
+
+ void traverseStatesWithBuffers(std::function<void(const layer_state_t&)> visitor);
+
+ FrameTimelineInfo frameTimelineInfo;
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
+ uint32_t flags;
+ sp<IBinder> applyToken;
+ InputWindowCommands inputWindowCommands;
+ int64_t desiredPresentTime;
+ bool isAutoTimestamp;
+ client_cache_t buffer;
+ int64_t postTime;
+ uint32_t permissions;
+ bool hasListenerCallbacks;
+ std::vector<ListenerCallbacks> listenerCallbacks;
+ int originPid;
+ int originUid;
+ uint64_t id;
+ std::shared_ptr<CountDownLatch> transactionCommittedSignal;
+};
+
+class CountDownLatch {
+public:
+ enum {
+ eSyncTransaction = 1 << 0,
+ eSyncInputWindows = 1 << 1,
+ };
+ explicit CountDownLatch(uint32_t flags) : mFlags(flags) {}
+
+ // True if there is no waiting condition after count down.
+ bool countDown(uint32_t flag) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mFlags == 0) {
+ return true;
+ }
+ mFlags &= ~flag;
+ if (mFlags == 0) {
+ mCountDownComplete.notify_all();
+ return true;
+ }
+ return false;
+ }
+
+ // Return true if triggered.
+ bool wait_until(const std::chrono::seconds& timeout) const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ const auto untilTime = std::chrono::system_clock::now() + timeout;
+ while (mFlags != 0) {
+ // Conditional variables can be woken up sporadically, so we check count
+ // to verify the wakeup was triggered by |countDown|.
+ if (std::cv_status::timeout == mCountDownComplete.wait_until(lock, untilTime)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+ uint32_t mFlags;
+ mutable std::condition_variable mCountDownComplete;
+ mutable std::mutex mMutex;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/common.proto b/services/surfaceflinger/layerproto/common.proto
index 1c73a9f..a6d8d61 100644
--- a/services/surfaceflinger/layerproto/common.proto
+++ b/services/surfaceflinger/layerproto/common.proto
@@ -18,6 +18,11 @@
option optimize_for = LITE_RUNTIME;
package android.surfaceflinger;
+message RegionProto {
+ reserved 1; // Previously: uint64 id
+ repeated RectProto rect = 2;
+}
+
message RectProto {
int32 left = 1;
int32 top = 2;
@@ -36,4 +41,51 @@
float dsdy = 3;
float dtdy = 4;
int32 type = 5;
-}
\ No newline at end of file
+}
+
+message ColorProto {
+ float r = 1;
+ float g = 2;
+ float b = 3;
+ float a = 4;
+}
+
+message InputWindowInfoProto {
+ uint32 layout_params_flags = 1;
+ int32 layout_params_type = 2;
+ RectProto frame = 3;
+ RegionProto touchable_region = 4;
+
+ int32 surface_inset = 5;
+ bool visible = 6;
+ bool can_receive_keys = 7 [deprecated = true];
+ bool focusable = 8;
+ bool has_wallpaper = 9;
+
+ float global_scale_factor = 10;
+ float window_x_scale = 11 [deprecated = true];
+ float window_y_scale = 12 [deprecated = true];
+
+ int32 crop_layer_id = 13;
+ bool replace_touchable_region_with_crop = 14;
+ RectProto touchable_region_crop = 15;
+ TransformProto transform = 16;
+}
+
+message BlurRegion {
+ uint32 blur_radius = 1;
+ uint32 corner_radius_tl = 2;
+ uint32 corner_radius_tr = 3;
+ uint32 corner_radius_bl = 4;
+ float corner_radius_br = 5;
+ float alpha = 6;
+ int32 left = 7;
+ int32 top = 8;
+ int32 right = 9;
+ int32 bottom = 10;
+}
+
+message ColorTransformProto {
+ // This will be a 4x4 matrix of float values
+ repeated float val = 1;
+}
diff --git a/services/surfaceflinger/layerproto/include/layerproto/TransactionProto.h b/services/surfaceflinger/layerproto/include/layerproto/TransactionProto.h
new file mode 100644
index 0000000..3e9ca52
--- /dev/null
+++ b/services/surfaceflinger/layerproto/include/layerproto/TransactionProto.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+// disable the warnings emitted from the protobuf headers. This file should be included instead of
+// directly including the generated header file
+#pragma GCC system_header
+#include <transactions.pb.h>
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 057eabb..4529905 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -143,11 +143,6 @@
float y = 2;
}
-message RegionProto {
- reserved 1; // Previously: uint64 id
- repeated RectProto rect = 2;
-}
-
message FloatRectProto {
float left = 1;
float top = 2;
@@ -162,13 +157,6 @@
int32 format = 4;
}
-message ColorProto {
- float r = 1;
- float g = 2;
- float b = 3;
- float a = 4;
-}
-
message BarrierLayerProto {
// layer id the barrier is waiting on.
int32 id = 1;
@@ -176,42 +164,3 @@
uint64 frame_number = 2;
}
-message InputWindowInfoProto {
- uint32 layout_params_flags = 1;
- uint32 layout_params_type = 2;
- RectProto frame = 3;
- RegionProto touchable_region = 4;
-
- uint32 surface_inset = 5;
- bool visible = 6;
- bool can_receive_keys = 7 [deprecated=true];
- bool focusable = 8;
- bool has_wallpaper = 9;
-
- float global_scale_factor = 10;
- float window_x_scale = 11 [deprecated=true];
- float window_y_scale = 12 [deprecated=true];
-
- uint32 crop_layer_id = 13;
- bool replace_touchable_region_with_crop = 14;
- RectProto touchable_region_crop = 15;
- TransformProto transform = 16;
-}
-
-message ColorTransformProto {
- // This will be a 4x4 matrix of float values
- repeated float val = 1;
-}
-
-message BlurRegion {
- uint32 blur_radius = 1;
- uint32 corner_radius_tl = 2;
- uint32 corner_radius_tr = 3;
- uint32 corner_radius_bl = 4;
- float corner_radius_br = 5;
- float alpha = 6;
- int32 left = 7;
- int32 top = 8;
- int32 right = 9;
- int32 bottom = 10;
-}
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
new file mode 100644
index 0000000..e7fb180
--- /dev/null
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -0,0 +1,244 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+option optimize_for = LITE_RUNTIME;
+
+import "frameworks/native/services/surfaceflinger/layerproto/common.proto";
+
+package android.surfaceflinger.proto;
+
+/* Represents a file full of surface flinger transactions.
+ Encoded, it should start with 0x54 0x4E 0x58 0x54 0x52 0x41 0x43 0x45 (.TNXTRACE), such
+ that they can be easily identified. */
+message TransactionTraceFile {
+ /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+ (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+ constants into .proto files. */
+ enum MagicNumber {
+ INVALID = 0;
+ MAGIC_NUMBER_L = 0x54584E54; /* TNXT (little-endian ASCII) */
+ MAGIC_NUMBER_H = 0x45434152; /* RACE (little-endian ASCII) */
+ }
+
+ fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
+ repeated TransactionTraceEntry entry = 2;
+}
+
+message TransactionTraceEntry {
+ int64 elapsed_time = 1;
+ int64 vsync_id = 2;
+ repeated TransactionState transactions = 3;
+}
+
+message TransactionState {
+ string tag = 2;
+ int32 pid = 3;
+ int32 uid = 4;
+ int64 vsync_id = 5;
+ int32 input_event_id = 6;
+ int64 post_time = 7;
+ repeated LayerState layer_changes = 9;
+ repeated DisplayState new_displays = 10;
+ repeated DisplayState display_changes = 11;
+}
+
+// Keep insync with layer_state_t
+message LayerState {
+ int32 layer_id = 1;
+ // Changes are split into ChangesLsb and ChangesMsb. First 32 bits are in ChangesLsb
+ // and the next 32 bits are in ChangesMsb. This is needed because enums have to be
+ // 32 bits and there's no nice way to put 64bit constants into .proto files.
+ enum ChangesLsb {
+ eChangesLsbNone = 0;
+ ePositionChanged = 0x00000001;
+ eLayerChanged = 0x00000002;
+ eSizeChanged = 0x00000004;
+ eAlphaChanged = 0x00000008;
+ eMatrixChanged = 0x00000010;
+ eTransparentRegionChanged = 0x00000020;
+ eFlagsChanged = 0x00000040;
+ eLayerStackChanged = 0x00000080;
+ eReleaseBufferListenerChanged = 0x00000400;
+ eShadowRadiusChanged = 0x00000800;
+ eLayerCreated = 0x00001000;
+ eBufferCropChanged = 0x00002000;
+ eRelativeLayerChanged = 0x00004000;
+ eReparent = 0x00008000;
+ eColorChanged = 0x00010000;
+ eDestroySurface = 0x00020000;
+ eTransformChanged = 0x00040000;
+ eTransformToDisplayInverseChanged = 0x00080000;
+ eCropChanged = 0x00100000;
+ eBufferChanged = 0x00200000;
+ eAcquireFenceChanged = 0x00400000;
+ eDataspaceChanged = 0x00800000;
+ eHdrMetadataChanged = 0x01000000;
+ eSurfaceDamageRegionChanged = 0x02000000;
+ eApiChanged = 0x04000000;
+ eSidebandStreamChanged = 0x08000000;
+ eColorTransformChanged = 0x10000000;
+ eHasListenerCallbacksChanged = 0x20000000;
+ eInputInfoChanged = 0x40000000;
+ eCornerRadiusChanged = -2147483648; // 0x80000000; (proto stores enums as signed int)
+ };
+ enum ChangesMsb {
+ eChangesMsbNone = 0;
+ eDestinationFrameChanged = 0x1;
+ eCachedBufferChanged = 0x2;
+ eBackgroundColorChanged = 0x4;
+ eMetadataChanged = 0x8;
+ eColorSpaceAgnosticChanged = 0x10;
+ eFrameRateSelectionPriority = 0x20;
+ eFrameRateChanged = 0x40;
+ eBackgroundBlurRadiusChanged = 0x80;
+ eProducerDisconnect = 0x100;
+ eFixedTransformHintChanged = 0x200;
+ eFrameNumberChanged = 0x400;
+ eBlurRegionsChanged = 0x800;
+ eAutoRefreshChanged = 0x1000;
+ eStretchChanged = 0x2000;
+ eTrustedOverlayChanged = 0x4000;
+ eDropInputModeChanged = 0x8000;
+ };
+ uint64 what = 2;
+ float x = 3;
+ float y = 4;
+ int32 z = 5;
+ uint32 w = 6;
+ uint32 h = 7;
+ uint32 layer_stack = 8;
+
+ enum Flags {
+ eFlagsNone = 0;
+ eLayerHidden = 0x01;
+ eLayerOpaque = 0x02;
+ eLayerSkipScreenshot = 0x40;
+ eLayerSecure = 0x80;
+ eEnableBackpressure = 0x100;
+ };
+ uint32 flags = 10;
+ uint32 mask = 11;
+
+ message Matrix22 {
+ float dsdx = 1;
+ float dtdx = 2;
+ float dtdy = 3;
+ float dsdy = 4;
+ };
+ Matrix22 matrix = 12;
+ float corner_radius = 13;
+ uint32 background_blur_radius = 14;
+ int32 parent_id = 15;
+ int32 relative_parent_id = 16;
+
+ float alpha = 50;
+ message Color3 {
+ float r = 1;
+ float g = 2;
+ float b = 3;
+ }
+ Color3 color = 18;
+ RegionProto transparent_region = 19;
+ uint32 transform = 20;
+ bool transform_to_display_inverse = 21;
+ RectProto crop = 49;
+
+ message BufferData {
+ uint64 buffer_id = 1;
+ uint32 width = 2;
+ uint32 height = 3;
+ uint64 frame_number = 5;
+
+ enum BufferDataChange {
+ BufferDataChangeNone = 0;
+ fenceChanged = 0x01;
+ frameNumberChanged = 0x02;
+ cachedBufferChanged = 0x04;
+ }
+ uint32 flags = 6;
+ uint64 cached_buffer_id = 7;
+ }
+ BufferData buffer_data = 23;
+ int32 api = 24;
+ bool has_sideband_stream = 25;
+ ColorTransformProto color_transform = 26;
+ repeated BlurRegion blur_regions = 27;
+
+ message Transform {
+ float dsdx = 1;
+ float dtdx = 2;
+ float dtdy = 3;
+ float dsdy = 4;
+ float tx = 5;
+ float ty = 6;
+ }
+ message WindowInfo {
+ uint32 layout_params_flags = 1;
+ int32 layout_params_type = 2;
+ RegionProto touchable_region = 4;
+ int32 surface_inset = 5;
+ bool focusable = 8;
+ bool has_wallpaper = 9;
+ float global_scale_factor = 10;
+ int32 crop_layer_id = 13;
+ bool replace_touchable_region_with_crop = 14;
+ RectProto touchable_region_crop = 15;
+ Transform transform = 16;
+ }
+ WindowInfo window_info_handle = 28;
+ float bg_color_alpha = 31;
+ int32 bg_color_dataspace = 32;
+ bool color_space_agnostic = 33;
+ float shadow_radius = 34;
+ int32 frame_rate_selection_priority = 35;
+ float frame_rate = 36;
+ int32 frame_rate_compatibility = 37;
+ int32 change_frame_rate_strategy = 38;
+ uint32 fixed_transform_hint = 39;
+ uint64 frame_number = 40;
+ bool auto_refresh = 41;
+ bool is_trusted_overlay = 42;
+ RectProto buffer_crop = 44;
+ RectProto destination_frame = 45;
+
+ enum DropInputMode {
+ NONE = 0;
+ ALL = 1;
+ OBSCURED = 2;
+ };
+ DropInputMode drop_input_mode = 48;
+}
+
+message DisplayState {
+ enum Changes {
+ eChangesNone = 0;
+ eSurfaceChanged = 0x01;
+ eLayerStackChanged = 0x02;
+ eDisplayProjectionChanged = 0x04;
+ eDisplaySizeChanged = 0x08;
+ eFlagsChanged = 0x10;
+ };
+ int32 id = 1;
+ uint32 what = 2;
+ uint32 flags = 3;
+ uint32 layer_stack = 4;
+ uint32 orientation = 5;
+ RectProto layer_stack_space_rect = 6;
+ RectProto oriented_display_space_rect = 7;
+ uint32 width = 8;
+ uint32 height = 9;
+}
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index 94e1e0c..ce94dab 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -28,8 +28,8 @@
#include <limits>
+#include <gui/test/CallbackUtils.h>
#include "BufferGenerator.h"
-#include "utils/CallbackUtils.h"
#include "utils/ColorUtils.h"
#include "utils/TransactionUtils.h"
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index e8759e5..91a5b52 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -18,8 +18,8 @@
#include <gui/DisplayEventReceiver.h>
+#include <gui/test/CallbackUtils.h>
#include "LayerTransactionTest.h"
-#include "utils/CallbackUtils.h"
using namespace std::chrono_literals;
@@ -1029,4 +1029,60 @@
EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
+// b202394221
+TEST_F(LayerCallbackTest, EmptyBufferStateChanges) {
+ sp<SurfaceControl> bufferLayer, emptyBufferLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(emptyBufferLayer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ int err = fillTransaction(transaction, &callback, bufferLayer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ ui::Size bufferSize = getBufferSize();
+
+ TransactionUtils::setFrame(transaction, bufferLayer,
+ Rect(0, 0, bufferSize.width, bufferSize.height),
+ Rect(0, 0, 32, 32));
+ transaction.setPosition(emptyBufferLayer, 1 + i, 2 + i);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, bufferLayer,
+ ExpectedResult::Buffer::ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, emptyBufferLayer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::NOT_RELEASED);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+// b202394221
+TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED));
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.setPosition(layer, 1, 2);
+ transaction.apply();
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index e5872c1..9cb617a 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -208,6 +208,37 @@
}
}
+// b/200781179 - don't round a layer without a valid crop
+// This behaviour should be fixed since we treat buffer layers differently than
+// effect or container layers.
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusInvalidCrop) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::GREEN, size, size));
+ ASSERT_NO_FATAL_FAILURE(child = createColorLayer("child", Color::RED));
+
+ Transaction().setCornerRadius(child, cornerRadius).reparent(child, parent).show(child).apply();
+ {
+ const uint8_t bottom = size - 1;
+ const uint8_t right = size - 1;
+ auto shot = getScreenCapture();
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+ // Solid corners since we don't round a layer without a valid crop
+ shot->expectColor(Rect(0, 0, testArea, testArea), Color::RED);
+ shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::RED);
+ shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::RED);
+ shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::RED);
+ // Solid center
+ shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
+ size / 2 + testArea / 2, size / 2 + testArea / 2),
+ Color::RED);
+ }
+}
+
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) {
sp<SurfaceControl> parent;
sp<SurfaceControl> child;
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 3847a51..f6b0def 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+#include <gui/test/CallbackUtils.h>
#include "LayerTransactionTest.h"
-#include "utils/CallbackUtils.h"
using namespace std::chrono_literals;
@@ -31,7 +31,7 @@
public:
static void function(void* callbackContext, ReleaseCallbackId callbackId,
const sp<Fence>& releaseFence,
- uint32_t /*currentMaxAcquiredBufferCount*/) {
+ std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {
if (!callbackContext) {
FAIL() << "failed to get callback context";
}
@@ -61,7 +61,7 @@
std::this_thread::sleep_for(300ms);
std::lock_guard lock(mMutex);
- EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+ EXPECT_EQ(mCallbackDataQueue.size(), 0U) << "extra callbacks received";
mCallbackDataQueue = {};
}
@@ -385,4 +385,84 @@
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
+TEST_F(ReleaseBufferCallbackTest, DISABLED_SetBuffer_OverwriteBuffers) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Create transaction with a buffer.
+ Transaction transaction;
+ transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ firstBufferCallbackId, releaseCallback->getCallback());
+
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ // Call setBuffer on the same transaction with a different buffer.
+ transaction.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+ secondBufferCallbackId, releaseCallback->getCallback());
+
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Create transaction with a buffer.
+ Transaction transaction1;
+ transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ firstBufferCallbackId, releaseCallback->getCallback());
+
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ // Create a second transaction with a new buffer for the same layer.
+ Transaction transaction2;
+ transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+ secondBufferCallbackId, releaseCallback->getCallback());
+
+ // merge transaction1 into transaction2 so ensure we get a proper buffer release callback.
+ transaction1.merge(std::move(transaction2));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) {
+ sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
+ sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+
+ TransactionCompletedListener::setInstance(firstCompletedListener);
+
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ Transaction transaction1;
+ transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ firstBufferCallbackId, releaseCallback->getCallback());
+
+ // Sent a second buffer to allow the first buffer to get released.
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ Transaction transaction2;
+ transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+ secondBufferCallbackId, releaseCallback->getCallback());
+
+ // Set a different TransactionCompletedListener to mimic a second process
+ TransactionCompletedListener::setInstance(secondCompletedListener);
+ Transaction().merge(std::move(transaction1)).merge(std::move(transaction2)).apply();
+
+ // Make sure we can still get the release callback even though the merge happened in a different
+ // process.
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
} // namespace android
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 078b0d4..f152ced 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -91,6 +91,7 @@
"TimerTest.cpp",
"TransactionApplicationTest.cpp",
"TransactionFrameTracerTest.cpp",
+ "TransactionProtoParserTest.cpp",
"TransactionSurfaceFrameTest.cpp",
"TunnelModeEnabledReporterTest.cpp",
"StrongTypingTest.cpp",
@@ -115,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",
@@ -149,6 +154,7 @@
"android.hardware.graphics.common@1.2",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libEGL",
"libfmq",
@@ -172,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/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 5135ff9..40ef6e7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -202,8 +202,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
- mFlinger.onMessageReceived(MessageQueue::REFRESH);
+ mFlinger.commitAndComposite();
LayerCase::cleanup(this);
}
@@ -215,8 +214,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
- mFlinger.onMessageReceived(MessageQueue::REFRESH);
+ mFlinger.commitAndComposite();
LayerCase::cleanup(this);
}
@@ -247,10 +245,16 @@
"screenshot"),
*mRenderEngine, true);
- status_t result =
- mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
- forSystem, regionSampling);
- EXPECT_EQ(NO_ERROR, result);
+ auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
+ forSystem, regionSampling);
+ EXPECT_TRUE(result.valid());
+
+ auto& [status, drawFence] = result.get();
+
+ EXPECT_EQ(NO_ERROR, status);
+ if (drawFence.ok()) {
+ sync_wait(drawFence.get(), -1);
+ }
LayerCase::cleanup(this);
}
@@ -346,9 +350,9 @@
static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>&,
+ const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&,
- const bool, base::unique_fd &&)
+ const bool, base::unique_fd&&)
-> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -397,9 +401,9 @@
Return(0)));
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>&,
+ const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&,
- const bool, base::unique_fd &&)
+ const bool, base::unique_fd&&)
-> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -537,7 +541,7 @@
ASSERT_EQ(NO_ERROR, err);
Mock::VerifyAndClear(test->mRenderEngine);
- EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1);
enqueueBuffer(test, layer);
Mock::VerifyAndClearExpectations(test->mMessageQueue);
@@ -633,9 +637,9 @@
static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::vector<renderengine::LayerSettings>& layerSettings,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -652,16 +656,16 @@
"verification lambda";
return resultFuture;
}
- const renderengine::LayerSettings* layer = layerSettings.back();
- EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
- EXPECT_THAT(layer->source.buffer.fence, Not(IsNull()));
- EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName);
- EXPECT_EQ(false, layer->source.buffer.isY410BT2020);
- EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha);
- EXPECT_EQ(false, layer->source.buffer.isOpaque);
- EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
- EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
+ const renderengine::LayerSettings layer = layerSettings.back();
+ EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
+ EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
+ EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
+ EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
+ EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
+ EXPECT_EQ(false, layer.source.buffer.isOpaque);
+ EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
return resultFuture;
});
}
@@ -685,9 +689,9 @@
static void setupREColorCompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::vector<renderengine::LayerSettings>& layerSettings,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -704,14 +708,14 @@
"setupREColorCompositionCallExpectations verification lambda";
return resultFuture;
}
- const renderengine::LayerSettings* layer = layerSettings.back();
- EXPECT_THAT(layer->source.buffer.buffer, IsNull());
+ const renderengine::LayerSettings layer = layerSettings.back();
+ EXPECT_THAT(layer.source.buffer.buffer, IsNull());
EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
LayerProperties::COLOR[2]),
- layer->source.solidColor);
- EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
- EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
+ layer.source.solidColor);
+ EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
return resultFuture;
});
}
@@ -765,9 +769,9 @@
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::vector<renderengine::LayerSettings>& layerSettings,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -784,12 +788,12 @@
"verification lambda";
return resultFuture;
}
- const renderengine::LayerSettings* layer = layerSettings.back();
- EXPECT_THAT(layer->source.buffer.buffer, IsNull());
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor);
- EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
- EXPECT_EQ(1.0f, layer->alpha);
+ const renderengine::LayerSettings layer = layerSettings.back();
+ EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
+ EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+ EXPECT_EQ(1.0f, layer.alpha);
return resultFuture;
});
}
@@ -883,7 +887,7 @@
test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
// Layer should be unregistered with scheduler.
- test->mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+ test->mFlinger.commit();
EXPECT_EQ(0, test->mFlinger.scheduler()->layerHistorySize());
}
};
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 28d0222..cb690aa 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -28,6 +28,7 @@
#include "AsyncCallRecorder.h"
#include "DisplayHardware/DisplayMode.h"
+#include "FrameTimeline.h"
#include "Scheduler/EventThread.h"
using namespace std::chrono_literals;
@@ -96,6 +97,8 @@
ConnectionEventRecorder& connectionEventRecorder,
nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
+ void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
+ nsecs_t preferredDeadline);
void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
@@ -120,6 +123,7 @@
std::unique_ptr<impl::EventThread> mThread;
sp<MockEventThreadConnection> mConnection;
sp<MockEventThreadConnection> mThrottledConnection;
+ std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager;
static constexpr uid_t mConnectionUid = 443;
static constexpr uid_t mThrottledConnectionUid = 177;
@@ -173,8 +177,8 @@
return VSYNC_PERIOD.count();
};
- mThread = std::make_unique<impl::EventThread>(std::move(source),
- /*tokenManager=*/nullptr,
+ mTokenManager = std::make_unique<frametimeline::impl::TokenManager>();
+ mThread = std::make_unique<impl::EventThread>(std::move(source), mTokenManager.get(),
mInterceptVSyncCallRecorder.getInvocable(),
throttleVsync, getVsyncPeriod);
@@ -247,6 +251,36 @@
expectedCount);
}
+void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
+ nsecs_t preferredDeadline) {
+ auto args = mConnectionEventCallRecorder.waitForCall();
+ ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp "
+ << expectedTimestamp;
+ const auto& event = std::get<0>(args.value());
+ for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) {
+ if (i > 0) {
+ EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp,
+ event.vsync.frameTimelines[i - 1].deadlineTimestamp)
+ << "Deadline timestamp out of order for frame timeline " << i;
+ EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp,
+ event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp)
+ << "Expected vsync timestamp out of order for frame timeline " << i;
+ }
+ if (event.vsync.frameTimelines[i].deadlineTimestamp == preferredDeadline) {
+ EXPECT_EQ(i, event.vsync.preferredFrameTimelineIndex)
+ << "Preferred frame timeline index should be " << i;
+ // For the platform-preferred frame timeline, the vsync ID is 0 because the first frame
+ // timeline is made before the rest.
+ EXPECT_EQ(0, event.vsync.frameTimelines[i].vsyncId)
+ << "Vsync ID incorrect for frame timeline " << i;
+ } else {
+ // Vsync ID 0 is used for the preferred frame timeline.
+ EXPECT_EQ(i + 1, event.vsync.frameTimelines[i].vsyncId)
+ << "Vsync ID incorrect for frame timeline " << i;
+ }
+ }
+}
+
void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected) {
auto args = mConnectionEventCallRecorder.waitForCall();
@@ -344,6 +378,19 @@
expectVSyncSetEnabledCallReceived(false);
}
+TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) {
+ // Signal that we want the next vsync event to be posted to the connection
+ mThread->requestNextVsync(mConnection);
+
+ expectVSyncSetEnabledCallReceived(true);
+
+ // Use the received callback to signal a vsync event.
+ // The interceptor should receive the event, as well as the connection.
+ mCallback->onVSyncEvent(123, 456, 789);
+ expectInterceptCallReceived(123);
+ expectVsyncEventFrameTimelinesCorrect(123, 789);
+}
+
TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
// Create a first connection, register it, and request a vsync rate of zero.
ConnectionEventRecorder firstConnectionEventRecorder{0};
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/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index dbd51fe..17d1dd6 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -31,62 +31,51 @@
using CallbackToken = scheduler::VSyncDispatch::CallbackToken;
+struct NoOpCompositor final : ICompositor {
+ bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
+ void composite(nsecs_t) override {}
+ void sample() override {}
+} gNoOpCompositor;
+
class TestableMessageQueue : public impl::MessageQueue {
-public:
- class MockHandler : public MessageQueue::Handler {
- public:
- explicit MockHandler(MessageQueue& queue) : MessageQueue::Handler(queue) {}
- ~MockHandler() override = default;
- MOCK_METHOD2(dispatchInvalidate, void(int64_t vsyncId, nsecs_t expectedVSyncTimestamp));
+ struct MockHandler : MessageQueue::Handler {
+ using MessageQueue::Handler::Handler;
+
+ MOCK_METHOD(void, dispatchCommit, (int64_t, nsecs_t), (override));
};
- TestableMessageQueue() = default;
- ~TestableMessageQueue() override = default;
+ explicit TestableMessageQueue(sp<MockHandler> handler)
+ : impl::MessageQueue(gNoOpCompositor, handler), mHandler(std::move(handler)) {}
- void initHandler(const sp<MockHandler>& handler) { mHandler = handler; }
+public:
+ TestableMessageQueue() : TestableMessageQueue(sp<MockHandler>::make(*this)) {}
- void triggerVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
- vsyncCallback(vsyncTime, targetWakeupTime, readyTime);
- }
+ using impl::MessageQueue::vsyncCallback;
+
+ const sp<MockHandler> mHandler;
};
-class MockVSyncDispatch : public scheduler::VSyncDispatch {
-public:
- MockVSyncDispatch() = default;
- ~MockVSyncDispatch() override = default;
-
+struct MockVSyncDispatch : scheduler::VSyncDispatch {
MOCK_METHOD2(registerCallback,
- CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
+ CallbackToken(const std::function<void(nsecs_t, nsecs_t, nsecs_t)>&, std::string));
MOCK_METHOD1(unregisterCallback, void(CallbackToken));
MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
-class MockTokenManager : public frametimeline::TokenManager {
-public:
- MockTokenManager() = default;
- ~MockTokenManager() override = default;
-
+struct MockTokenManager : frametimeline::TokenManager {
MOCK_METHOD1(generateTokenForPredictions, int64_t(frametimeline::TimelineItem&& prediction));
MOCK_CONST_METHOD1(getPredictionsForToken, std::optional<frametimeline::TimelineItem>(int64_t));
};
-class MessageQueueTest : public testing::Test {
-public:
- MessageQueueTest() = default;
- ~MessageQueueTest() override = default;
-
+struct MessageQueueTest : testing::Test {
void SetUp() override {
- EXPECT_NO_FATAL_FAILURE(mEventQueue.initHandler(mHandler));
-
EXPECT_CALL(mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken));
EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, mDuration));
EXPECT_CALL(mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
}
- sp<TestableMessageQueue::MockHandler> mHandler =
- new TestableMessageQueue::MockHandler(mEventQueue);
MockVSyncDispatch mVSyncDispatch;
MockTokenManager mTokenManager;
TestableMessageQueue mEventQueue;
@@ -100,45 +89,49 @@
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(MessageQueueTest, invalidate) {
+TEST_F(MessageQueueTest, commit) {
const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
.readyDuration = 0,
.earliestVsync = 0};
- EXPECT_FALSE(mEventQueue.nextExpectedInvalidate().has_value());
+ EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
- EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
- EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value());
- EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count());
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+
+ ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
+ EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
}
-TEST_F(MessageQueueTest, invalidateTwice) {
+TEST_F(MessageQueueTest, commitTwice) {
InSequence s;
const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
.readyDuration = 0,
.earliestVsync = 0};
EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
- EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
- EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value());
- EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count());
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+
+ ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
+ EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567));
- EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
- EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value());
- EXPECT_EQ(4567, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count());
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+
+ ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
+ EXPECT_EQ(4567, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
}
-TEST_F(MessageQueueTest, invalidateTwiceWithCallback) {
+TEST_F(MessageQueueTest, commitTwiceWithCallback) {
InSequence s;
const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
.readyDuration = 0,
.earliestVsync = 0};
EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
- EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
- EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value());
- EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count());
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+
+ ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
+ EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
const auto startTime = 100;
const auto endTime = startTime + mDuration.count();
@@ -148,10 +141,10 @@
generateTokenForPredictions(
frametimeline::TimelineItem(startTime, endTime, presentTime)))
.WillOnce(Return(vsyncId));
- EXPECT_CALL(*mHandler, dispatchInvalidate(vsyncId, presentTime)).Times(1);
- EXPECT_NO_FATAL_FAILURE(mEventQueue.triggerVsyncCallback(presentTime, startTime, endTime));
+ EXPECT_CALL(*mEventQueue.mHandler, dispatchCommit(vsyncId, presentTime)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.vsyncCallback(presentTime, startTime, endTime));
- EXPECT_FALSE(mEventQueue.nextExpectedInvalidate().has_value());
+ EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
const auto timingAfterCallback =
scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
@@ -159,10 +152,10 @@
.earliestVsync = presentTime};
EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0));
- EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
}
-TEST_F(MessageQueueTest, invalidateWithDurationChange) {
+TEST_F(MessageQueueTest, commitWithDurationChange) {
EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(mDifferentDuration));
const auto timing =
@@ -171,7 +164,7 @@
.earliestVsync = 0};
EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0));
- EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
}
} // 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 84fa1e2..3b40965 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();
@@ -172,11 +172,9 @@
}
namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
TEST_P(SetFrameRateTest, SetAndGet) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
@@ -187,7 +185,7 @@
}
TEST_P(SetFrameRateTest, SetAndGetParent) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
@@ -212,7 +210,7 @@
}
TEST_P(SetFrameRateTest, SetAndGetParentAllVote) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
@@ -251,7 +249,7 @@
}
TEST_P(SetFrameRateTest, SetAndGetChild) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
@@ -276,7 +274,7 @@
}
TEST_P(SetFrameRateTest, SetAndGetChildAllVote) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
@@ -315,7 +313,7 @@
}
TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
@@ -345,7 +343,7 @@
}
TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
@@ -376,7 +374,7 @@
}
TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
@@ -470,12 +468,12 @@
.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) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
const auto& layerFactory = GetParam();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index 2362a31..8c30341 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -51,8 +51,8 @@
// --------------------------------------------------------------------
// Cleanup conditions
- // Destroying the display invalidates the display state.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ // Creating the display commits a display transaction.
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
}
TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) {
@@ -86,9 +86,9 @@
// --------------------------------------------------------------------
// Cleanup conditions
- // Destroying the display invalidates the display state.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ // Creating the display commits a display transaction.
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
}
} // namespace
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
index e2be074..7087fb6 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
@@ -40,8 +40,8 @@
// The call should notify the interceptor that a display was created.
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
- // Destroying the display invalidates the display state.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ // Destroying the display commits a display transaction.
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
// --------------------------------------------------------------------
// Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
index bd89397..29ff0cd 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
@@ -38,9 +38,8 @@
// --------------------------------------------------------------------
// Call Expectations
- // We expect invalidate() to be invoked once to trigger display transaction
- // processing.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ // We expect a scheduled commit for the display transaction.
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
// --------------------------------------------------------------------
// Invocation
@@ -86,9 +85,8 @@
// --------------------------------------------------------------------
// Call Expectations
- // We expect invalidate() to be invoked once to trigger display transaction
- // processing.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ // We expect a scheduled commit for the display transaction.
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
// --------------------------------------------------------------------
// Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index bafa910..e1b44cf 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -46,9 +46,8 @@
// We expect a call to get the active display config.
Case::Display::setupHwcGetActiveConfigCallExpectations(this);
- // We expect invalidate() to be invoked once to trigger display transaction
- // processing.
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ // We expect a scheduled commit for the display transaction.
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 6502420..6edebd4 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -260,6 +260,11 @@
auto display = Display::makeFakeExistingDisplayInjector(test);
display.inject();
display.mutableDisplayDevice()->setPowerMode(mode);
+ if (display.mutableDisplayDevice()->isInternal()) {
+ test->mFlinger.mutableActiveDisplayToken() =
+ display.mutableDisplayDevice()->getDisplayToken();
+ }
+
return display;
}
@@ -268,7 +273,7 @@
}
static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1);
}
static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 7072439..c23fcc7 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -73,8 +73,8 @@
return nullptr;
}
- std::unique_ptr<MessageQueue> createMessageQueue() override {
- return std::make_unique<android::impl::MessageQueue>();
+ std::unique_ptr<MessageQueue> createMessageQueue(ICompositor& compositor) override {
+ return std::make_unique<android::impl::MessageQueue>(compositor);
}
std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
@@ -296,6 +296,16 @@
* Forwarding for functions being tested
*/
+ nsecs_t commit() {
+ constexpr int64_t kVsyncId = 123;
+ const nsecs_t now = systemTime();
+ const nsecs_t expectedVsyncTime = now + 10'000'000;
+ mFlinger->commit(now, kVsyncId, expectedVsyncTime);
+ return now;
+ }
+
+ void commitAndComposite() { mFlinger->composite(commit()); }
+
auto createDisplay(const String8& displayName, bool secure) {
return mFlinger->createDisplay(displayName, secure);
}
@@ -343,10 +353,6 @@
return mFlinger->setPowerModeInternal(display, mode);
}
- auto onMessageReceived(int32_t what) {
- return mFlinger->onMessageReceived(what, /*vsyncId=*/0, systemTime());
- }
-
auto renderScreenImplLocked(const RenderArea& renderArea,
SurfaceFlinger::TraverseLayersFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer,
@@ -440,6 +446,7 @@
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) {
return mFlinger->fromHandle(handle);
@@ -761,7 +768,7 @@
};
private:
- void scheduleRefresh(FrameHint) override {}
+ void scheduleComposite(FrameHint) override {}
void setVsyncEnabled(bool) override {}
void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {}
void kernelTimerChanged(bool) override {}
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 1a50427..05551b4 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -103,7 +103,7 @@
static_assert(0xffffffffffffffff == static_cast<uint64_t>(-1));
};
- void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) {
+ void checkEqual(TransactionInfo info, TransactionState state) {
EXPECT_EQ(0u, info.states.size());
EXPECT_EQ(0u, state.states.size());
@@ -126,8 +126,7 @@
void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
- // called in SurfaceFlinger::signalTransaction
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
TransactionInfo transaction;
setupSingle(transaction, flags, syncInputWindows,
/*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
@@ -157,8 +156,7 @@
void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
- // called in SurfaceFlinger::signalTransaction
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
// first check will see desired present time has not passed,
// but afterwards it will look like the desired present time has passed
@@ -187,12 +185,11 @@
void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
- // called in SurfaceFlinger::signalTransaction
nsecs_t time = systemTime();
if (!syncInputWindows) {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(2);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(2);
} else {
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
}
// transaction that should go on the pending thread
TransactionInfo transactionA;
@@ -255,8 +252,7 @@
TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
- // called in SurfaceFlinger::signalTransaction
- EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
TransactionInfo transactionA; // transaction to go on pending queue
setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
new file mode 100644
index 0000000..cebd451
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <limits> // std::numeric_limits
+
+#include <gui/SurfaceComposerClient.h>
+
+#include "Tracing/TransactionProtoParser.h"
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+TEST(TransactionProtoParserTest, parse) {
+ const sp<IBinder> layerHandle = new BBinder();
+ const sp<IBinder> displayHandle = new BBinder();
+ TransactionState t1;
+ t1.originPid = 1;
+ t1.originUid = 2;
+ t1.frameTimelineInfo.vsyncId = 3;
+ t1.frameTimelineInfo.inputEventId = 4;
+ t1.postTime = 5;
+
+ layer_state_t layer;
+ layer.layerId = 6;
+ layer.what = std::numeric_limits<uint64_t>::max();
+ layer.x = 7;
+ layer.matrix.dsdx = 15;
+
+ size_t layerCount = 2;
+ t1.states.reserve(layerCount);
+ for (uint32_t i = 0; i < layerCount; i++) {
+ ComposerState s;
+ if (i == 1) {
+ layer.parentSurfaceControlForChild =
+ new SurfaceControl(SurfaceComposerClient::getDefault(), layerHandle, nullptr,
+ 42);
+ }
+ s.state = layer;
+ t1.states.add(s);
+ }
+
+ size_t displayCount = 2;
+ t1.displays.reserve(displayCount);
+ for (uint32_t i = 0; i < displayCount; i++) {
+ DisplayState display;
+ display.what = std::numeric_limits<uint32_t>::max();
+ if (i == 0) {
+ display.token = displayHandle;
+ } else {
+ display.token = nullptr;
+ }
+ display.width = 85;
+ t1.displays.add(display);
+ }
+
+ std::function<int32_t(const sp<IBinder>&)> getLayerIdFn = [&](const sp<IBinder>& handle) {
+ return (handle == layerHandle) ? 42 : -1;
+ };
+ std::function<int32_t(const sp<IBinder>&)> getDisplayIdFn = [&](const sp<IBinder>& handle) {
+ return (handle == displayHandle) ? 43 : -1;
+ };
+ std::function<sp<IBinder>(int32_t)> getLayerHandleFn = [&](int32_t id) {
+ return (id == 42) ? layerHandle : nullptr;
+ };
+ std::function<sp<IBinder>(int32_t)> getDisplayHandleFn = [&](int32_t id) {
+ return (id == 43) ? displayHandle : nullptr;
+ };
+
+ proto::TransactionState proto =
+ TransactionProtoParser::toProto(t1, getLayerIdFn, getDisplayIdFn);
+ TransactionState t2 =
+ TransactionProtoParser::fromProto(proto, getLayerHandleFn, getDisplayHandleFn);
+
+ ASSERT_EQ(t1.originPid, t2.originPid);
+ ASSERT_EQ(t1.originUid, t2.originUid);
+ ASSERT_EQ(t1.frameTimelineInfo.vsyncId, t2.frameTimelineInfo.vsyncId);
+ ASSERT_EQ(t1.frameTimelineInfo.inputEventId, t2.frameTimelineInfo.inputEventId);
+ ASSERT_EQ(t1.postTime, t2.postTime);
+ ASSERT_EQ(t1.states.size(), t2.states.size());
+ ASSERT_EQ(t1.states[0].state.x, t2.states[0].state.x);
+ ASSERT_EQ(t1.states[0].state.matrix.dsdx, t2.states[0].state.matrix.dsdx);
+ ASSERT_EQ(t1.states[1].state.parentSurfaceControlForChild->getHandle(),
+ t2.states[1].state.parentSurfaceControlForChild->getHandle());
+
+ ASSERT_EQ(t1.displays.size(), t2.displays.size());
+ ASSERT_EQ(t1.displays[1].width, t2.displays[1].width);
+ ASSERT_EQ(t1.displays[0].token, t2.displays[0].token);
+}
+
+} // 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/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index 0e7b320..d684337 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -29,17 +29,18 @@
MessageQueue();
~MessageQueue() override;
- MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
MOCK_METHOD1(setInjector, void(sp<EventThreadConnection>));
MOCK_METHOD0(waitMessage, void());
MOCK_METHOD1(postMessage, void(sp<MessageHandler>&&));
- MOCK_METHOD0(invalidate, void());
- MOCK_METHOD0(refresh, void());
MOCK_METHOD3(initVsync,
void(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
std::chrono::nanoseconds));
MOCK_METHOD1(setDuration, void(std::chrono::nanoseconds workDuration));
- MOCK_METHOD0(nextExpectedInvalidate, std::optional<std::chrono::steady_clock::time_point>());
+
+ MOCK_METHOD(void, scheduleCommit, (), (override));
+ MOCK_METHOD(void, scheduleComposite, (), (override));
+
+ MOCK_METHOD(std::optional<Clock::time_point>, getScheduledFrameTime, (), (const, override));
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 291559f..e241dc9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -23,7 +23,7 @@
namespace android::mock {
struct SchedulerCallback final : ISchedulerCallback {
- MOCK_METHOD(void, scheduleRefresh, (FrameHint), (override));
+ MOCK_METHOD(void, scheduleComposite, (FrameHint), (override));
MOCK_METHOD1(setVsyncEnabled, void(bool));
MOCK_METHOD2(changeRefreshRate,
void(const scheduler::RefreshRateConfigs::RefreshRate&,
@@ -33,7 +33,7 @@
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
- void scheduleRefresh(FrameHint) override {}
+ void scheduleComposite(FrameHint) override {}
void setVsyncEnabled(bool) override {}
void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent) override {}
diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS
new file mode 100644
index 0000000..d073e2b
--- /dev/null
+++ b/services/vibratorservice/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
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{