Merge "SurfaceFlinger HWC overlay API"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 260ee8d..f54f132 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -56,6 +56,9 @@
},
{
"include-filter": "*RefreshRateOverlayTest.*"
+ },
+ {
+ "exclude-filter": "*ChildLayerTest#ChildrenSurviveParentDestruction"
}
]
},
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 5cd2dea..48d48ac 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -193,9 +193,9 @@
{ OPT, "events/ext4/ext4_da_write_end/enable" },
{ OPT, "events/ext4/ext4_sync_file_enter/enable" },
{ OPT, "events/ext4/ext4_sync_file_exit/enable" },
- { REQ, "events/block/block_bio_queue/enable" },
- { REQ, "events/block/block_bio_complete/enable" },
- { REQ, "events/ufs/ufshcd_command/enable" },
+ { OPT, "events/block/block_bio_queue/enable" },
+ { OPT, "events/block/block_bio_complete/enable" },
+ { OPT, "events/ufs/ufshcd_command/enable" },
} },
{ "mmc", "eMMC commands", 0, {
{ REQ, "events/mmc/enable" },
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index a60972b..a62bd01 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -126,6 +126,7 @@
],
required: [
"atrace",
+ "bugreport_procdump",
"dmabuf_dump",
"ip",
"iptables",
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0b69829..b076c15 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -183,6 +183,7 @@
#define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
#define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace"
#define CGROUPFS_DIR "/sys/fs/cgroup"
+#define SDK_EXT_INFO "/apex/com.android.sdkext/bin/derive_sdk"
// TODO(narayan): Since this information has to be kept in sync
// with tombstoned, we should just put it in a common header.
@@ -766,7 +767,7 @@
}
void Dumpstate::PrintHeader() const {
- std::string build, fingerprint, radio, bootloader, network;
+ std::string build, fingerprint, radio, bootloader, network, sdkversion;
char date[80];
build = android::base::GetProperty("ro.build.display.id", "(unknown)");
@@ -774,6 +775,7 @@
radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
+ sdkversion = android::base::GetProperty("ro.build.version.sdk", "(unknown)");
strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
printf("========================================================\n");
@@ -791,9 +793,10 @@
if (module_metadata_version != 0) {
printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
}
- printf("SDK extension versions [r=%s s=%s]\n",
- android::base::GetProperty("build.version.extensions.r", "-").c_str(),
- android::base::GetProperty("build.version.extensions.s", "-").c_str());
+ printf("Android SDK version: %s\n", sdkversion.c_str());
+ printf("SDK extensions: ");
+ RunCommandToFd(STDOUT_FILENO, "", {SDK_EXT_INFO, "--header"},
+ CommandOptions::WithTimeout(1).Always().DropRoot().Build());
printf("Kernel: ");
DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
@@ -1026,7 +1029,7 @@
MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
return;
}
- RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
+ RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(20).Build());
bool empty = 0 == lseek(fd, 0, SEEK_END);
if (!empty) {
// Use a different name from "incident.proto"
@@ -1049,7 +1052,7 @@
return;
}
RunCommandToFd(fd, "", {"dumpsys", "netstats", "--proto"},
- CommandOptions::WithTimeout(120).Build());
+ CommandOptions::WithTimeout(5).Build());
bool empty = 0 == lseek(fd, 0, SEEK_END);
if (!empty) {
ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "netstats" + kProtoExt,
@@ -1084,7 +1087,7 @@
return;
}
RunCommandToFd(fd, "", {"cmd", "window", "dump-visible-window-views"},
- CommandOptions::WithTimeout(120).Build());
+ CommandOptions::WithTimeout(10).Build());
bool empty = 0 == lseek(fd, 0, SEEK_END);
if (!empty) {
ds.AddZipEntry("visible_windows.zip", path);
@@ -1423,7 +1426,9 @@
// Dump all of the files that make up the vendor interface.
// See the files listed in dumpFileList() for the latest list of files.
static void DumpVintf() {
- const auto vintfFiles = android::vintf::details::dumpFileList();
+
+ const std::string sku = android::base::GetProperty("ro.boot.product.hardware.sku", "");
+ const auto vintfFiles = android::vintf::details::dumpFileList(sku);
for (const auto vintfFile : vintfFiles) {
struct stat st;
if (stat(vintfFile.c_str(), &st) == 0) {
@@ -1619,7 +1624,8 @@
RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
"pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "BUGREPORT_PROCDUMP", {"bugreport_procdump"},
+ CommandOptions::AS_ROOT);
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpVisibleWindowViews);
@@ -1636,9 +1642,6 @@
RunCommand("PROCESSES AND THREADS",
{"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
- CommandOptions::AS_ROOT);
-
if (ds.dump_pool_) {
WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals));
} else {
@@ -1668,8 +1671,6 @@
RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
-
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
@@ -1890,6 +1891,9 @@
DumpFile("PSI memory", "/proc/pressure/memory");
DumpFile("PSI io", "/proc/pressure/io");
+ RunCommand("SDK EXTENSIONS", {SDK_EXT_INFO, "--dump"},
+ CommandOptions::WithTimeout(10).Always().DropRoot().Build());
+
if (dump_pool_) {
RETURN_IF_USER_DENIED_CONSENT();
WaitForTask(std::move(dump_traces));
@@ -3914,15 +3918,6 @@
return;
}
-void do_showmap(int pid, const char *name) {
- char title[255];
- char arg[255];
-
- snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
- snprintf(arg, sizeof(arg), "%d", pid);
- RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
-}
-
int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
DurationReporter duration_reporter(title);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ee6b1ae..66f84cb 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -619,9 +619,6 @@
/* Displays a processes times */
void show_showtime(int pid, const char *name);
-/* Runs "showmap" for a process */
-void do_showmap(int pid, const char *name);
-
/* Gets the dmesg output for the kernel */
void do_dmesg();
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 01f7d30..c163095 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -35,9 +35,12 @@
GLHelper::~GLHelper() {
}
-bool GLHelper::setUp(const ShaderDesc* shaderDescs, size_t numShaders) {
+bool GLHelper::setUp(const sp<IBinder>& displayToken, const ShaderDesc* shaderDescs,
+ size_t numShaders) {
bool result;
+ mDisplayToken = displayToken;
+
mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (mDisplay == EGL_NO_DISPLAY) {
fprintf(stderr, "eglGetDisplay error: %#x\n", eglGetError());
@@ -221,14 +224,8 @@
}
bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
- const sp<IBinder> dpy = mSurfaceComposerClient->getInternalDisplayToken();
- if (dpy == nullptr) {
- fprintf(stderr, "SurfaceComposer::getInternalDisplayToken failed.\n");
- return false;
- }
-
ui::DisplayMode mode;
- status_t err = mSurfaceComposerClient->getActiveDisplayMode(dpy, &mode);
+ status_t err = mSurfaceComposerClient->getActiveDisplayMode(mDisplayToken, &mode);
if (err != NO_ERROR) {
fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err);
return false;
diff --git a/cmds/flatland/GLHelper.h b/cmds/flatland/GLHelper.h
index d09463a..5194f50 100644
--- a/cmds/flatland/GLHelper.h
+++ b/cmds/flatland/GLHelper.h
@@ -44,7 +44,7 @@
~GLHelper();
- bool setUp(const ShaderDesc* shaderDescs, size_t numShaders);
+ bool setUp(const sp<IBinder>& displayToken, const ShaderDesc* shaderDescs, size_t numShaders);
void tearDown();
@@ -87,6 +87,8 @@
size_t mNumShaders;
GLuint mDitherTexture;
+
+ sp<IBinder> mDisplayToken;
};
} // namespace android
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index 7ceb397..6d14d56 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -20,6 +20,7 @@
#include <gui/SurfaceControl.h>
#include <gui/GLConsumer.h>
#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
#include <ui/Fence.h>
#include <utils/Trace.h>
@@ -34,9 +35,10 @@
using namespace ::android;
-static uint32_t g_SleepBetweenSamplesMs = 0;
-static bool g_PresentToWindow = false;
-static size_t g_BenchmarkNameLen = 0;
+static uint32_t g_SleepBetweenSamplesMs = 0;
+static bool g_PresentToWindow = false;
+static size_t g_BenchmarkNameLen = 0;
+static sp<IBinder> g_DisplayToken = nullptr;
struct BenchmarkDesc {
// The name of the test.
@@ -393,7 +395,7 @@
uint32_t h = mDesc.runHeights[mInstance];
mGLHelper = new GLHelper();
- result = mGLHelper->setUp(shaders, NELEMS(shaders));
+ result = mGLHelper->setUp(g_DisplayToken, shaders, NELEMS(shaders));
if (!result) {
return false;
}
@@ -718,13 +720,17 @@
}
// Print the command usage help to stderr.
-static void showHelp(const char *cmd) {
- fprintf(stderr, "usage: %s [options]\n", cmd);
- fprintf(stderr, "options include:\n"
- " -s N sleep for N ms between samples\n"
- " -d display the test frame to a window\n"
- " --help print this helpful message and exit\n"
- );
+static void showHelp(const char* cmd) {
+ fprintf(stderr, "usage: %s [options]\n", cmd);
+ fprintf(
+ stderr,
+ "options include:\n"
+ " -s N sleep for N ms between samples\n"
+ " -d display the test frame to a window\n"
+ " -i display-id specify a display ID to use for multi-display device\n"
+ " see \"dumpsys SurfaceFlinger --display-id\" for valid "
+ "display IDs\n"
+ " --help print this helpful message and exit\n");
}
int main(int argc, char** argv) {
@@ -733,6 +739,14 @@
exit(0);
}
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ if (ids.empty()) {
+ fprintf(stderr, "Failed to get ID for any displays.\n");
+ exit(3);
+ }
+
+ std::optional<PhysicalDisplayId> displayId;
+
for (;;) {
int ret;
int option_index = 0;
@@ -741,7 +755,7 @@
{ 0, 0, 0, 0 }
};
- ret = getopt_long(argc, argv, "ds:",
+ ret = getopt_long(argc, argv, "ds:i:",
long_options, &option_index);
if (ret < 0) {
@@ -757,6 +771,14 @@
g_SleepBetweenSamplesMs = atoi(optarg);
break;
+ case 'i':
+ displayId = DisplayId::fromValue<PhysicalDisplayId>(atoll(optarg));
+ if (!displayId) {
+ fprintf(stderr, "Invalid display ID: %s.\n", optarg);
+ exit(4);
+ }
+ break;
+
case 0:
if (strcmp(long_options[option_index].name, "help")) {
showHelp(argv[0]);
@@ -770,6 +792,22 @@
}
}
+ if (!displayId) { // no display id is specified
+ if (ids.size() == 1) {
+ displayId = ids.front();
+ } else {
+ fprintf(stderr, "Please specify a display ID for multi-display device.\n");
+ showHelp(argv[0]);
+ exit(5);
+ }
+ }
+
+ g_DisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
+ if (g_DisplayToken == nullptr) {
+ fprintf(stderr, "SurfaceComposer::getPhysicalDisplayToken failed.\n");
+ exit(6);
+ }
+
g_BenchmarkNameLen = maxBenchmarkNameLen();
printf(" cmdline:");
@@ -782,4 +820,6 @@
fprintf(stderr, "exiting due to error.\n");
return 1;
}
+
+ return 0;
}
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index e978e79..6a3120c 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -27,6 +27,7 @@
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/wait.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -504,6 +505,11 @@
return 0;
}
+ if (WIFSIGNALED(dexopt_result)) {
+ LOG(WARNING) << "Interrupted by signal " << WTERMSIG(dexopt_result) ;
+ return dexopt_result;
+ }
+
// If this was a profile-guided run, we may have profile version issues. Try to downgrade,
// if possible.
if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
diff --git a/cmds/installd/otapreopt.rc b/cmds/installd/otapreopt.rc
index 059ae75..0bad0c5 100644
--- a/cmds/installd/otapreopt.rc
+++ b/cmds/installd/otapreopt.rc
@@ -5,4 +5,4 @@
# The dalvik-cache was not moved itself, so as to restrict the rights of otapreopt_slot.
# But now the relabeling is annoying as there is no force option available here. So
# explicitly list all the ISAs we know.
- restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/mips /data/dalvik-cache/mips64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
+ restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/riscv64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 0727383..3681d5b 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -49,14 +49,14 @@
#ifdef __ANDROID_RECOVERY__
auto vintfObject = vintf::VintfObjectRecovery::GetInstance();
if (vintfObject == nullptr) {
- LOG(ERROR) << "NULL VintfObjectRecovery!";
+ ALOGE("NULL VintfObjectRecovery!");
return {};
}
return {ManifestWithDescription{vintfObject->getRecoveryHalManifest(), "recovery"}};
#else
auto vintfObject = vintf::VintfObject::GetInstance();
if (vintfObject == nullptr) {
- LOG(ERROR) << "NULL VintfObject!";
+ ALOGE("NULL VintfObject!");
return {};
}
return {ManifestWithDescription{vintfObject->getDeviceHalManifest(), "device"},
@@ -68,10 +68,10 @@
static bool forEachManifest(const std::function<bool(const ManifestWithDescription&)>& func) {
for (const ManifestWithDescription& mwd : GetManifestsWithDescription()) {
if (mwd.manifest == nullptr) {
- LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
- // note, we explicitly do not retry here, so that we can detect VINTF
- // or other bugs (b/151696835)
- continue;
+ ALOGE("NULL VINTF MANIFEST!: %s", mwd.description);
+ // note, we explicitly do not retry here, so that we can detect VINTF
+ // or other bugs (b/151696835)
+ continue;
}
if (func(mwd)) return true;
}
@@ -87,8 +87,9 @@
size_t firstSlash = name.find('/');
size_t lastDot = name.rfind('.', firstSlash);
if (firstSlash == std::string::npos || lastDot == std::string::npos) {
- LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
- << "some.package.foo.IFoo/default) but got: " << name;
+ ALOGE("VINTF HALs require names in the format type/instance (e.g. "
+ "some.package.foo.IFoo/default) but got: %s",
+ name.c_str());
return false;
}
aname->package = name.substr(0, lastDot);
@@ -104,7 +105,7 @@
bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
- LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
+ ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description);
return true; // break
}
return false; // continue
@@ -113,8 +114,8 @@
if (!found) {
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- LOG(INFO) << "Could not find " << aname.package << "." << aname.iface << "/"
- << aname.instance << " in the VINTF manifest.";
+ ALOGI("Could not find %s.%s/%s in the VINTF manifest.", aname.package.c_str(),
+ aname.iface.c_str(), aname.instance.c_str());
}
return found;
@@ -173,7 +174,9 @@
static std::vector<std::string> getVintfInstances(const std::string& interface) {
size_t lastDot = interface.rfind('.');
if (lastDot == std::string::npos) {
- LOG(ERROR) << "VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) but got: " << interface;
+ ALOGE("VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) "
+ "but got: %s",
+ interface.c_str());
return {};
}
const std::string package = interface.substr(0, lastDot);
@@ -308,7 +311,7 @@
}
if (!isValidServiceName(name)) {
- LOG(ERROR) << "Invalid service name: " << name;
+ ALOGE("Invalid service name: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");
}
@@ -322,20 +325,44 @@
// implicitly unlinked when the binder is removed
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
- LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ ALOGE("Could not linkToDeath when adding %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
}
+ auto it = mNameToService.find(name);
+ if (it != mNameToService.end()) {
+ const Service& existing = it->second;
+
+ // We could do better than this because if the other service dies, it
+ // may not have an entry here. However, this case is unlikely. We are
+ // only trying to detect when two different services are accidentally installed.
+
+ if (existing.ctx.uid != ctx.uid) {
+ ALOGW("Service '%s' originally registered from UID %u but it is now being registered "
+ "from UID %u. Multiple instances installed?",
+ name.c_str(), existing.ctx.uid, ctx.uid);
+ }
+
+ if (existing.ctx.sid != ctx.sid) {
+ ALOGW("Service '%s' originally registered from SID %s but it is now being registered "
+ "from SID %s. Multiple instances installed?",
+ name.c_str(), existing.ctx.sid.c_str(), ctx.sid.c_str());
+ }
+
+ ALOGI("Service '%s' originally registered from PID %d but it is being registered again "
+ "from PID %d. Bad state? Late death notification? Multiple instances installed?",
+ name.c_str(), existing.ctx.debugPid, ctx.debugPid);
+ }
+
// Overwrite the old service if it exists
- mNameToService[name] = Service {
- .binder = binder,
- .allowIsolated = allowIsolated,
- .dumpPriority = dumpPriority,
- .debugPid = ctx.debugPid,
+ mNameToService[name] = Service{
+ .binder = binder,
+ .allowIsolated = allowIsolated,
+ .dumpPriority = dumpPriority,
+ .ctx = ctx,
};
- auto it = mNameToRegistrationCallback.find(name);
- if (it != mNameToRegistrationCallback.end()) {
+ if (auto it = mNameToRegistrationCallback.find(name); it != mNameToRegistrationCallback.end()) {
for (const sp<IServiceCallback>& cb : it->second) {
mNameToService[name].guaranteeClient = true;
// permission checked in registerForNotifications
@@ -381,7 +408,7 @@
}
if (!isValidServiceName(name)) {
- LOG(ERROR) << "Invalid service name: " << name;
+ ALOGE("Invalid service name: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
@@ -392,7 +419,7 @@
if (OK !=
IInterface::asBinder(callback)->linkToDeath(
sp<ServiceManager>::fromExisting(this))) {
- LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ ALOGE("Could not linkToDeath when adding %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -424,7 +451,7 @@
}
if (!found) {
- LOG(ERROR) << "Trying to unregister callback, but none exists " << name;
+ ALOGE("Trying to unregister callback, but none exists %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -546,10 +573,11 @@
std::thread([=] {
if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) {
- LOG(INFO) << "Tried to start aidl service " << name
- << " as a lazy service, but was unable to. Usually this happens when a "
- "service is not installed, but if the service is intended to be used as a "
- "lazy service, then it may be configured incorrectly.";
+ ALOGI("Tried to start aidl service %s as a lazy service, but was unable to. Usually "
+ "this happens when a "
+ "service is not installed, but if the service is intended to be used as a "
+ "lazy service, then it may be configured incorrectly.",
+ name.c_str());
}
}).detach();
}
@@ -567,24 +595,25 @@
auto serviceIt = mNameToService.find(name);
if (serviceIt == mNameToService.end()) {
- LOG(ERROR) << "Could not add callback for nonexistent service: " << name;
+ ALOGE("Could not add callback for nonexistent service: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
- if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) {
- LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")";
+ if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
+ ALOGW("Only a server can register for client callbacks (for %s)", name.c_str());
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
}
if (serviceIt->second.binder != service) {
- LOG(WARNING) << "Tried to register client callback for " << name
- << " but a different service is registered under this name.";
+ ALOGW("Tried to register client callback for %s but a different service is registered "
+ "under this name.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
if (OK !=
IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) {
- LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name;
+ ALOGE("Could not linkToDeath when adding client callback for %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -669,7 +698,7 @@
void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) {
auto serviceIt = mNameToService.find(serviceName);
if (serviceIt == mNameToService.end()) {
- LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName;
+ ALOGW("sendClientCallbackNotifications could not find service %s", serviceName.c_str());
return;
}
Service& service = serviceIt->second;
@@ -677,7 +706,7 @@
CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients
<< " so we can't tell clients again that we have client: " << hasClients;
- LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients;
+ ALOGI("Notifying %s they have clients: %d", serviceName.c_str(), hasClients);
auto ccIt = mNameToClientCallback.find(serviceName);
CHECK(ccIt != mNameToClientCallback.end())
@@ -702,26 +731,26 @@
auto serviceIt = mNameToService.find(name);
if (serviceIt == mNameToService.end()) {
- LOG(WARNING) << "Tried to unregister " << name
- << ", but that service wasn't registered to begin with.";
+ ALOGW("Tried to unregister %s, but that service wasn't registered to begin with.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) {
- LOG(WARNING) << "Only a server can unregister itself (for " << name << ")";
+ if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
+ ALOGW("Only a server can unregister itself (for %s)", name.c_str());
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
}
sp<IBinder> storedBinder = serviceIt->second.binder;
if (binder != storedBinder) {
- LOG(WARNING) << "Tried to unregister " << name
- << ", but a different service is registered under this name.";
+ ALOGW("Tried to unregister %s, but a different service is registered under this name.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
if (serviceIt->second.guaranteeClient) {
- LOG(INFO) << "Tried to unregister " << name << ", but there is about to be a client.";
+ ALOGI("Tried to unregister %s, but there is about to be a client.", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -734,7 +763,7 @@
// So, if clients > 2, then at least one other service on the system must hold a refcount.
if (clients < 0 || clients > 2) {
// client callbacks are either disabled or there are other clients
- LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients;
+ ALOGI("Tried to unregister %s, but there are clients: %d", name.c_str(), clients);
// Set this flag to ensure the clients are acknowledged in the next callback
serviceIt->second.guaranteeClient = true;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
@@ -754,7 +783,7 @@
for (auto const& [name, service] : mNameToService) {
ServiceDebugInfo info;
info.name = name;
- info.debugPid = service.debugPid;
+ info.debugPid = service.ctx.debugPid;
outReturn->push_back(std::move(info));
}
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index c6db697..07b79f8 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -74,7 +74,7 @@
int32_t dumpPriority;
bool hasClients = false; // notifications sent on true -> false.
bool guaranteeClient = false; // forces the client check to true
- pid_t debugPid = 0; // the process in which this service runs
+ Access::CallingContext ctx; // process that originally registers this
// the number of clients of the service, including servicemanager itself
ssize_t getNodeStrongRefCount();
diff --git a/cmds/surfacereplayer/Android.bp b/cmds/surfacereplayer/Android.bp
deleted file mode 100644
index 34fc8b1..0000000
--- a/cmds/surfacereplayer/Android.bp
+++ /dev/null
@@ -1,13 +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"],
-}
-
-subdirs = [
- "proto",
- "replayer",
-]
diff --git a/cmds/surfacereplayer/OWNERS b/cmds/surfacereplayer/OWNERS
deleted file mode 100644
index 32bcc83..0000000
--- a/cmds/surfacereplayer/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/frameworks/native:/services/surfaceflinger/OWNERS
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
deleted file mode 100644
index 23b54ee..0000000
--- a/cmds/surfacereplayer/proto/Android.bp
+++ /dev/null
@@ -1,23 +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"],
-}
-
-cc_library_static {
- name: "libtrace_proto",
- srcs: [
- "src/trace.proto",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- proto: {
- type: "lite",
- export_proto_headers: true,
- },
-}
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
deleted file mode 100644
index a177027..0000000
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ /dev/null
@@ -1,225 +0,0 @@
-syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-package android.surfaceflinger;
-
-message Trace {
- repeated Increment increment = 1;
-}
-
-message Increment {
- required int64 time_stamp = 1;
-
- oneof increment {
- Transaction transaction = 2;
- SurfaceCreation surface_creation = 3;
- SurfaceDeletion surface_deletion = 4;
- BufferUpdate buffer_update = 5;
- VSyncEvent vsync_event = 6;
- DisplayCreation display_creation = 7;
- DisplayDeletion display_deletion = 8;
- PowerModeUpdate power_mode_update = 9;
- }
-}
-
-message Transaction {
- repeated SurfaceChange surface_change = 1;
- repeated DisplayChange display_change = 2;
-
- required bool synchronous = 3;
- required bool animation = 4;
- optional Origin origin = 5;
- optional uint64 id = 6;
-}
-
-message SurfaceChange {
- required int32 id = 1;
- reserved 7;
- oneof SurfaceChange {
- PositionChange position = 2;
- SizeChange size = 3;
- AlphaChange alpha = 4;
- LayerChange layer = 5;
- CropChange crop = 6;
- MatrixChange matrix = 8;
- TransparentRegionHintChange transparent_region_hint = 10;
- LayerStackChange layer_stack = 11;
- HiddenFlagChange hidden_flag = 12;
- OpaqueFlagChange opaque_flag = 13;
- SecureFlagChange secure_flag = 14;
- CornerRadiusChange corner_radius = 16;
- ReparentChange reparent = 17;
- RelativeParentChange relative_parent = 18;
- BackgroundBlurRadiusChange background_blur_radius = 20;
- ShadowRadiusChange shadow_radius = 21;
- BlurRegionsChange blur_regions = 22;
- TrustedOverlayChange trusted_overlay = 23;
- }
-}
-
-message PositionChange {
- required float x = 1;
- required float y = 2;
-}
-
-message SizeChange {
- required uint32 w = 1;
- required uint32 h = 2;
-}
-
-message AlphaChange {
- required float alpha = 1;
-}
-
-message CornerRadiusChange {
- required float corner_radius = 1;
-}
-
-message BackgroundBlurRadiusChange {
- required float background_blur_radius = 1;
-}
-
-message LayerChange {
- required uint32 layer = 1;
-}
-
-message CropChange {
- required Rectangle rectangle = 1;
-}
-
-message MatrixChange {
- required float dsdx = 1;
- required float dtdx = 2;
- required float dsdy = 3;
- required float dtdy = 4;
-}
-
-message TransparentRegionHintChange {
- repeated Rectangle region = 1;
-}
-
-message LayerStackChange {
- required uint32 layer_stack = 1;
-}
-
-message DisplayFlagsChange {
- required uint32 flags = 1;
-}
-
-message HiddenFlagChange {
- required bool hidden_flag = 1;
-}
-
-message OpaqueFlagChange {
- required bool opaque_flag = 1;
-}
-
-message SecureFlagChange {
- required bool secure_flag = 1;
-}
-
-message DisplayChange {
- required int32 id = 1;
-
- oneof DisplayChange {
- DispSurfaceChange surface = 2;
- LayerStackChange layer_stack = 3;
- SizeChange size = 4;
- ProjectionChange projection = 5;
- DisplayFlagsChange flags = 6;
- }
-}
-
-message DispSurfaceChange {
- required uint64 buffer_queue_id = 1;
- required string buffer_queue_name = 2;
-}
-
-message ProjectionChange {
- required int32 orientation = 1;
- required Rectangle viewport = 2;
- required Rectangle frame = 3;
-}
-
-message Rectangle {
- required int32 left = 1;
- required int32 top = 2;
- required int32 right = 3;
- required int32 bottom = 4;
-}
-
-message SurfaceCreation {
- required int32 id = 1;
- required string name = 2;
- required uint32 w = 3;
- required uint32 h = 4;
-}
-
-message SurfaceDeletion {
- required int32 id = 1;
-}
-
-message BufferUpdate {
- required int32 id = 1;
- required uint32 w = 2;
- required uint32 h = 3;
- required uint64 frame_number = 4;
-}
-
-message VSyncEvent {
- required int64 when = 1;
-}
-
-message DisplayCreation {
- required int32 id = 1;
- required string name = 2;
- optional uint64 display_id = 3;
- required bool is_secure = 4;
-}
-
-message DisplayDeletion {
- required int32 id = 1;
-}
-
-message PowerModeUpdate {
- required int32 id = 1;
- required int32 mode = 2;
-}
-
-message ReparentChange {
- required int32 parent_id = 1;
-}
-
-message RelativeParentChange {
- required int32 relative_parent_id = 1;
- required int32 z = 2;
-}
-
-message ShadowRadiusChange {
- required float radius = 1;
-}
-
-message TrustedOverlayChange {
- required float is_trusted_overlay = 1;
-}
-
-message BlurRegionsChange {
- repeated BlurRegionChange blur_regions = 1;
-}
-
-message BlurRegionChange {
- required uint32 blur_radius = 1;
- required float corner_radius_tl = 2;
- required float corner_radius_tr = 3;
- required float corner_radius_bl = 4;
- required float corner_radius_br = 5;
- required float alpha = 6;
- required int32 left = 7;
- required int32 top = 8;
- required int32 right = 9;
- required int32 bottom = 10;
-}
-
-message Origin {
- required int32 pid = 1;
- required int32 uid = 2;
-}
diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp
deleted file mode 100644
index 3985230..0000000
--- a/cmds/surfacereplayer/replayer/Android.bp
+++ /dev/null
@@ -1,71 +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"],
-}
-
-cc_library_shared {
- name: "libsurfacereplayer",
- srcs: [
- "BufferQueueScheduler.cpp",
- "Event.cpp",
- "Replayer.cpp",
- ],
- cppflags: [
- "-Werror",
- "-Wno-unused-parameter",
- "-Wno-format",
- "-Wno-c++98-compat-pedantic",
- "-Wno-float-conversion",
- "-Wno-disabled-macro-expansion",
- "-Wno-float-equal",
- "-Wno-sign-conversion",
- "-Wno-padded",
- ],
- static_libs: [
- "libtrace_proto",
- ],
- shared_libs: [
- "libEGL",
- "libGLESv2",
- "libbinder",
- "liblog",
- "libcutils",
- "libgui",
- "libui",
- "libutils",
- "libprotobuf-cpp-lite",
- "libbase",
- "libnativewindow",
- ],
- export_include_dirs: [
- ".",
- ],
-}
-
-cc_binary {
- name: "surfacereplayer",
- srcs: [
- "Main.cpp",
- ],
- shared_libs: [
- "libprotobuf-cpp-lite",
- "libsurfacereplayer",
- "libutils",
- "libgui",
- ],
- static_libs: [
- "libtrace_proto",
- ],
- cppflags: [
- "-Werror",
- "-Wno-unused-parameter",
- "-Wno-c++98-compat-pedantic",
- "-Wno-float-conversion",
- "-Wno-disabled-macro-expansion",
- "-Wno-float-equal",
- ],
-}
diff --git a/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp b/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp
deleted file mode 100644
index 77de8dc..0000000
--- a/cmds/surfacereplayer/replayer/BufferQueueScheduler.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.
- */
-#define LOG_TAG "BufferQueueScheduler"
-
-#include "BufferQueueScheduler.h"
-
-#include <android/native_window.h>
-#include <gui/Surface.h>
-
-using namespace android;
-
-BufferQueueScheduler::BufferQueueScheduler(
- const sp<SurfaceControl>& surfaceControl, const HSV& color, int id)
- : mSurfaceControl(surfaceControl), mColor(color), mSurfaceId(id), mContinueScheduling(true) {}
-
-void BufferQueueScheduler::startScheduling() {
- ALOGV("Starting Scheduler for %d Layer", mSurfaceId);
- std::unique_lock<std::mutex> lock(mMutex);
- if (mSurfaceControl == nullptr) {
- mCondition.wait(lock, [&] { return (mSurfaceControl != nullptr); });
- }
-
- while (mContinueScheduling) {
- while (true) {
- if (mBufferEvents.empty()) {
- break;
- }
-
- BufferEvent event = mBufferEvents.front();
- lock.unlock();
-
- bufferUpdate(event.dimensions);
- fillSurface(event.event);
- mColor.modulate();
- lock.lock();
- mBufferEvents.pop();
- }
- mCondition.wait(lock);
- }
-}
-
-void BufferQueueScheduler::addEvent(const BufferEvent& event) {
- std::lock_guard<std::mutex> lock(mMutex);
- mBufferEvents.push(event);
- mCondition.notify_one();
-}
-
-void BufferQueueScheduler::stopScheduling() {
- std::lock_guard<std::mutex> lock(mMutex);
- mContinueScheduling = false;
- mCondition.notify_one();
-}
-
-void BufferQueueScheduler::setSurfaceControl(
- const sp<SurfaceControl>& surfaceControl, const HSV& color) {
- std::lock_guard<std::mutex> lock(mMutex);
- mSurfaceControl = surfaceControl;
- mColor = color;
- mCondition.notify_one();
-}
-
-void BufferQueueScheduler::bufferUpdate(const Dimensions& dimensions) {
- sp<Surface> s = mSurfaceControl->getSurface();
- s->setBuffersDimensions(dimensions.width, dimensions.height);
-}
-
-void BufferQueueScheduler::fillSurface(const std::shared_ptr<Event>& event) {
- ANativeWindow_Buffer outBuffer;
- sp<Surface> s = mSurfaceControl->getSurface();
-
- status_t status = s->lock(&outBuffer, nullptr);
-
- if (status != NO_ERROR) {
- ALOGE("fillSurface: failed to lock buffer, (%d)", status);
- return;
- }
-
- auto color = mColor.getRGB();
-
- auto img = reinterpret_cast<uint8_t*>(outBuffer.bits);
- for (int y = 0; y < outBuffer.height; y++) {
- for (int x = 0; x < outBuffer.width; x++) {
- uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
- pixel[0] = color.r;
- pixel[1] = color.g;
- pixel[2] = color.b;
- pixel[3] = LAYER_ALPHA;
- }
- }
-
- event->readyToExecute();
-
- status = s->unlockAndPost();
-
- ALOGE_IF(status != NO_ERROR, "fillSurface: failed to unlock and post buffer, (%d)", status);
-}
diff --git a/cmds/surfacereplayer/replayer/BufferQueueScheduler.h b/cmds/surfacereplayer/replayer/BufferQueueScheduler.h
deleted file mode 100644
index cb20fcc..0000000
--- a/cmds/surfacereplayer/replayer/BufferQueueScheduler.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_SURFACEREPLAYER_BUFFERQUEUESCHEDULER_H
-#define ANDROID_SURFACEREPLAYER_BUFFERQUEUESCHEDULER_H
-
-#include "Color.h"
-#include "Event.h"
-
-#include <gui/SurfaceControl.h>
-
-#include <utils/StrongPointer.h>
-
-#include <atomic>
-#include <condition_variable>
-#include <mutex>
-#include <queue>
-#include <utility>
-
-namespace android {
-
-auto constexpr LAYER_ALPHA = 190;
-
-struct Dimensions {
- Dimensions() = default;
- Dimensions(int w, int h) : width(w), height(h) {}
-
- int width = 0;
- int height = 0;
-};
-
-struct BufferEvent {
- BufferEvent() = default;
- BufferEvent(std::shared_ptr<Event> e, Dimensions d) : event(e), dimensions(d) {}
-
- std::shared_ptr<Event> event;
- Dimensions dimensions;
-};
-
-class BufferQueueScheduler {
- public:
- BufferQueueScheduler(const sp<SurfaceControl>& surfaceControl, const HSV& color, int id);
-
- void startScheduling();
- void addEvent(const BufferEvent&);
- void stopScheduling();
-
- void setSurfaceControl(const sp<SurfaceControl>& surfaceControl, const HSV& color);
-
- private:
- void bufferUpdate(const Dimensions& dimensions);
-
- // Lock and fill the surface, block until the event is signaled by the main loop,
- // then unlock and post the buffer.
- void fillSurface(const std::shared_ptr<Event>& event);
-
- sp<SurfaceControl> mSurfaceControl;
- HSV mColor;
- const int mSurfaceId;
-
- bool mContinueScheduling;
-
- std::queue<BufferEvent> mBufferEvents;
- std::mutex mMutex;
- std::condition_variable mCondition;
-};
-
-} // namespace android
-#endif
diff --git a/cmds/surfacereplayer/replayer/Color.h b/cmds/surfacereplayer/replayer/Color.h
deleted file mode 100644
index ce644be..0000000
--- a/cmds/surfacereplayer/replayer/Color.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_SURFACEREPLAYER_COLOR_H
-#define ANDROID_SURFACEREPLAYER_COLOR_H
-
-#include <cmath>
-#include <cstdlib>
-
-namespace android {
-
-constexpr double modulateFactor = .0001;
-constexpr double modulateLimit = .80;
-
-struct RGB {
- RGB(uint8_t rIn, uint8_t gIn, uint8_t bIn) : r(rIn), g(gIn), b(bIn) {}
-
- uint8_t r = 0;
- uint8_t g = 0;
- uint8_t b = 0;
-};
-
-struct HSV {
- HSV() = default;
- HSV(double hIn, double sIn, double vIn) : h(hIn), s(sIn), v(vIn) {}
-
- double h = 0;
- double s = 0;
- double v = 0;
-
- RGB getRGB() const;
-
- bool modulateUp = false;
-
- void modulate();
-};
-
-void inline HSV::modulate() {
- if(modulateUp) {
- v += modulateFactor;
- } else {
- v -= modulateFactor;
- }
-
- if(v <= modulateLimit || v >= 1) {
- modulateUp = !modulateUp;
- }
-}
-
-inline RGB HSV::getRGB() const {
- using namespace std;
- double r = 0, g = 0, b = 0;
-
- if (s == 0) {
- r = v;
- g = v;
- b = v;
- } else {
- auto tempHue = static_cast<int>(h) % 360;
- tempHue = tempHue / 60;
-
- int i = static_cast<int>(trunc(tempHue));
- double f = h - i;
-
- double x = v * (1.0 - s);
- double y = v * (1.0 - (s * f));
- double z = v * (1.0 - (s * (1.0 - f)));
-
- switch (i) {
- case 0:
- r = v;
- g = z;
- b = x;
- break;
-
- case 1:
- r = y;
- g = v;
- b = x;
- break;
-
- case 2:
- r = x;
- g = v;
- b = z;
- break;
-
- case 3:
- r = x;
- g = y;
- b = v;
- break;
-
- case 4:
- r = z;
- g = x;
- b = v;
- break;
-
- default:
- r = v;
- g = x;
- b = y;
- break;
- }
- }
-
- return RGB(round(r * 255), round(g * 255), round(b * 255));
-}
-}
-#endif
diff --git a/cmds/surfacereplayer/replayer/Event.cpp b/cmds/surfacereplayer/replayer/Event.cpp
deleted file mode 100644
index 64db5f0..0000000
--- a/cmds/surfacereplayer/replayer/Event.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-
-#include "Event.h"
-
-using namespace android;
-using Increment = surfaceflinger::Increment;
-
-Event::Event(Increment::IncrementCase type) : mIncrementType(type) {}
-
-void Event::readyToExecute() {
- changeState(Event::EventState::Waiting);
- waitUntil(Event::EventState::Signaled);
- changeState(Event::EventState::Running);
-}
-
-void Event::complete() {
- waitUntil(Event::EventState::Waiting);
- changeState(Event::EventState::Signaled);
- waitUntil(Event::EventState::Running);
-}
-
-void Event::waitUntil(Event::EventState state) {
- std::unique_lock<std::mutex> lock(mLock);
- mCond.wait(lock, [this, state] { return (mState == state); });
-}
-
-void Event::changeState(Event::EventState state) {
- std::unique_lock<std::mutex> lock(mLock);
- mState = state;
- lock.unlock();
-
- mCond.notify_one();
-}
-
-Increment::IncrementCase Event::getIncrementType() {
- return mIncrementType;
-}
diff --git a/cmds/surfacereplayer/replayer/Event.h b/cmds/surfacereplayer/replayer/Event.h
deleted file mode 100644
index 09a7c24..0000000
--- a/cmds/surfacereplayer/replayer/Event.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_SURFACEREPLAYER_EVENT_H
-#define ANDROID_SURFACEREPLAYER_EVENT_H
-
-#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
-
-#include <condition_variable>
-#include <mutex>
-
-namespace android {
-
-using Increment = surfaceflinger::Increment;
-
-class Event {
- public:
- Event(Increment::IncrementCase);
-
- enum class EventState {
- SettingUp, // Completing as much time-independent work as possible
- Waiting, // Waiting for signal from main thread to finish execution
- Signaled, // Signaled by main thread, about to immediately switch to Running
- Running // Finishing execution of rest of work
- };
-
- void readyToExecute();
- void complete();
-
- Increment::IncrementCase getIncrementType();
-
- private:
- void waitUntil(EventState state);
- void changeState(EventState state);
-
- std::mutex mLock;
- std::condition_variable mCond;
-
- EventState mState = EventState::SettingUp;
-
- Increment::IncrementCase mIncrementType;
-};
-}
-#endif
diff --git a/cmds/surfacereplayer/replayer/Main.cpp b/cmds/surfacereplayer/replayer/Main.cpp
deleted file mode 100644
index fbfcacf..0000000
--- a/cmds/surfacereplayer/replayer/Main.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Replayer - Main.cpp
- *
- * 1. Get flags from command line
- * 2. Commit actions or settings based on the flags
- * 3. Initalize a replayer object with the filename passed in
- * 4. Replay
- * 5. Exit successfully or print error statement
- */
-
-#include <Replayer.h>
-
-#include <csignal>
-#include <iostream>
-#include <stdlib.h>
-#include <unistd.h>
-
-using namespace android;
-
-void printHelpMenu() {
- std::cout << "SurfaceReplayer options:\n";
- std::cout << "Usage: surfacereplayer [OPTIONS...] <TRACE FILE>\n";
- std::cout << " File path must be absolute" << std::endl << std::endl;
-
- std::cout << " -m Stops the replayer at the start of the trace and switches ";
- "to manual replay\n";
-
- std::cout << "\n -t [Number of Threads] Specifies the number of threads to be used while "
- "replaying (default is " << android::DEFAULT_THREADS << ")\n";
-
- std::cout << "\n -s [Timestamp] Specify at what timestamp should the replayer switch "
- "to manual replay\n";
-
- std::cout << " -n Ignore timestamps and run through trace as fast as possible\n";
-
- std::cout << " -l Indefinitely loop the replayer\n";
-
- std::cout << " -h Display help menu\n";
-
- std::cout << std::endl;
-}
-
-int main(int argc, char** argv) {
- std::string filename;
- bool loop = false;
- bool wait = true;
- bool pauseBeginning = false;
- int numThreads = DEFAULT_THREADS;
- long stopHere = -1;
-
- int opt = 0;
- while ((opt = getopt(argc, argv, "mt:s:nlh?")) != -1) {
- switch (opt) {
- case 'm':
- pauseBeginning = true;
- break;
- case 't':
- numThreads = atoi(optarg);
- break;
- case 's':
- stopHere = atol(optarg);
- break;
- case 'n':
- wait = false;
- break;
- case 'l':
- loop = true;
- break;
- case 'h':
- case '?':
- printHelpMenu();
- exit(0);
- default:
- std::cerr << "Invalid argument...exiting" << std::endl;
- printHelpMenu();
- exit(0);
- }
- }
-
- char** input = argv + optind;
- if (input[0] == nullptr) {
- std::cerr << "No trace file provided...exiting" << std::endl;
- abort();
- }
- filename.assign(input[0]);
-
- status_t status = NO_ERROR;
- do {
- android::Replayer r(filename, pauseBeginning, numThreads, wait, stopHere);
- status = r.replay();
- } while(loop);
-
- if (status == NO_ERROR) {
- std::cout << "Successfully finished replaying trace" << std::endl;
- } else {
- std::cerr << "Trace replayer returned error: " << status << std::endl;
- }
-
- return 0;
-}
diff --git a/cmds/surfacereplayer/replayer/README.md b/cmds/surfacereplayer/replayer/README.md
deleted file mode 100644
index 893f0dc..0000000
--- a/cmds/surfacereplayer/replayer/README.md
+++ /dev/null
@@ -1,262 +0,0 @@
-SurfaceReplayer Documentation
-===================
-
-[go/SurfaceReplayer](go/SurfaceReplayer)
-
-SurfaceReplayer is a playback mechanism that allows the replaying of traces recorded by
-[SurfaceInterceptor](go/SurfaceInterceptor) from SurfaceFlinger. It specifically replays
-
-* Creation and deletion of surfaces/displays
-* Alterations to the surfaces/displays called Transactions
-* Buffer Updates to surfaces
-* VSync events
-
-At their specified times to be as close to the original trace.
-
-Usage
---------
-
-###Creating a trace
-
-SurfaceInterceptor is the mechanism used to create traces. The device needs to be rooted in order to
-utilize it. To allow it to write to the device, run
-
-`setenforce 0`
-
-To start recording a trace, run
-
-`service call SurfaceFlinger 1020 i32 1`
-
-To stop recording, run
-
-`service call SurfaceFlinger 1020 i32 0`
-
-The default location for the trace is `/data/SurfaceTrace.dat`
-
-###Executable
-
-To replay a specific trace, execute
-
-`/data/local/tmp/surfacereplayer /absolute/path/to/trace`
-
-inside the android shell. This will replay the full trace and then exit. Running this command
-outside of the shell by prepending `adb shell` will not allow for manual control and will not turn
-off VSync injections if it interrupted in any way other than fully replaying the trace
-
-The replay will not fill surfaces with their contents during the capture. Rather they are given a
-random color which will be the same every time the trace is replayed. Surfaces modulate their color
-at buffer updates.
-
-**Options:**
-
-- -m pause the replayer at the start of the trace for manual replay
-- -t [Number of Threads] uses specified number of threads to queue up actions (default is 3)
-- -s [Timestamp] switches to manual replay at specified timestamp
-- -n Ignore timestamps and run through trace as fast as possible
-- -l Indefinitely loop the replayer
-- -h displays help menu
-
-**Manual Replay:**
-When replaying, if the user presses CTRL-C, the replay will stop and can be manually controlled
-by the user. Pressing CTRL-C again will exit the replayer.
-
-Manual replaying is similar to debugging in gdb. A prompt is presented and the user is able to
-input commands to choose how to proceed by hitting enter after inputting a command. Pressing enter
-without inputting a command repeats the previous command.
-
-- n - steps the replayer to the next VSync event
-- ni - steps the replayer to the next increment
-- c - continues normal replaying
-- c [milliseconds] - continue until specified number of milliseconds have passed
-- s [timestamp] - continue and stop at specified timestamp
-- l - list out timestamp of current increment
-- h - displays help menu
-
-###Shared Library
-
-To use the shared library include these shared libraries
-
-`libsurfacereplayer`
-`libprotobuf-cpp-full`
-`libutils`
-
-And the static library
-
-`libtrace_proto`
-
-Include the replayer header at the top of your file
-
-`#include <replayer/Replayer.h>`
-
-There are two constructors for the replayer
-
-`Replayer(std::string& filename, bool replayManually, int numThreads, bool wait, nsecs_t stopHere)`
-`Replayer(Trace& trace, ... ditto ...)`
-
-The first constructor takes in the filepath where the trace is located and loads in the trace
-object internally.
-- replayManually - **True**: if the replayer will immediately switch to manual replay at the start
-- numThreads - Number of worker threads the replayer will use.
-- wait - **False**: Replayer ignores waits in between increments
-- stopHere - Time stamp of where the replayer should run to then switch to manual replay
-
-The second constructor includes all of the same parameters but takes in a preloaded trace object.
-To use add
-
-`#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>`
-
-To your file
-
-After initializing the Replayer call
-
- replayer.replay();
-
-And the trace will start replaying. Once the trace is finished replaying, the function will return.
-The layers that are visible at the end of the trace will remain on screen until the program
-terminates.
-
-
-**If VSyncs are broken after running the replayer** that means `enableVSyncInjections(false)` was
-never executed. This can be fixed by executing
-
-`service call SurfaceFlinger 23 i32 0`
-
-in the android shell
-
-Code Breakdown
--------------
-
-The Replayer is composed of 5 components.
-
-- The data format of the trace (Trace.proto)
-- The Replayer object (Replayer.cpp)
-- The synchronization mechanism to signal threads within the Replayer (Event.cpp)
-- The scheduler for buffer updates per surface (BufferQueueScheduler.cpp)
-- The Main executable (Main.cpp)
-
-### Traces
-
-Traces are represented as a protobuf message located in surfacereplayer/proto/src.
-
-**Traces** contain *repeated* **Increments** (events that have occurred in SurfaceFlinger).
-**Increments** contain the time stamp of when it occurred and a *oneof* which can be a
-
- - Transaction
- - SurfaceCreation
- - SurfaceDeletion
- - DisplayCreation
- - DisplayDeleteion
- - BufferUpdate
- - VSyncEvent
- - PowerModeUpdate
-
-**Transactions** contain whether the transaction was synchronous or animated and *repeated*
-**SurfaceChanges** and **DisplayChanges**
-
-- **SurfaceChanges** contain an id of the surface being manipulated and can be changes such as
-position, alpha, hidden, size, etc.
-- **DisplayChanges** contain the id of the display being manipulated and can be changes such as
-size, layer stack, projection, etc.
-
-**Surface/Display Creation** contain the id of the surface/display and the name of the
-surface/display
-
-**Surface/Display Deletion** contain the id of the surface/display to be deleted
-
-**Buffer Updates** contain the id of the surface who's buffer is being updated, the size of the
-buffer, and the frame number.
-
-**VSyncEvents** contain when the VSync event has occurred.
-
-**PowerModeUpdates** contain the id of the display being updated and what mode it is being
-changed to.
-
-To output the contents of a trace in a readable format, execute
-
-`**aprotoc** --decode=Trace \
--I=$ANDROID_BUILD_TOP/frameworks/native/cmds/surfacereplayer/proto/src \
-$ANDROID_BUILD_TOP/frameworks/native/cmds/surfacereplayer/proto/src/trace.proto \
- < **YourTraceFile.dat** > **YourOutputName.txt**`
-
-
-###Replayer
-
-Fundamentally the replayer loads a trace and iterates through each increment, waiting the required
-amount of time until the increment should be executed, then executing the increment. The first
-increment in a trace does not start at 0, rather the replayer treats its time stamp as time 0 and
-goes from there.
-
-Increments from the trace are played asynchronously rather than one by one, being dispatched by
-the main thread, queued up in a thread pool and completed when the main thread deems they are
-ready to finish execution.
-
-When an increment is dispatched, it completes as much work as it can before it has to be
-synchronized (e.g. prebaking a buffer for a BufferUpdate). When it gets to a critical action
-(e.g. locking and pushing a buffer), it waits for the main thread to complete it using an Event
-object. The main thread holds a queue of these Event objects and completes the
-corresponding Event base on its time stamp. After completing an increment, the main thread will
-dispatch another increment and continue.
-
-The main thread's execution flow is outlined below
-
- initReplay() //queue up the initial increments
- while(!pendingIncrements.empty()) { //while increments remaining
- event = pendingIncrement.pop();
- wait(event.time_stamp(); //waitUntil it is time to complete this increment
-
- event.complete() //signal to let event finish
- if(increments remaing()) {
- dispatchEvent() //queue up another increment
- }
- }
-
-A worker thread's flow looks like so
-
- //dispatched!
- Execute non-time sensitive work here
- ...
- event.readyToExecute() //time sensitive point...waiting for Main Thread
- ...
- Finish execution
-
-
-### Event
-
-An Event is a simple synchronization mechanism used to facilitate communication between the main
-and worker threads. Every time an increment is dispatched, an Event object is also created.
-
-An Event can be in 4 different states:
-
-- **SettingUp** - The worker is in the process of completing all non-time sensitive work
-- **Waiting** - The worker is waiting on the main thread to signal it.
-- **Signaled** - The worker has just been signaled by the main thread
-- **Running** - The worker is running again and finishing the rest of its work.
-
-When the main thread wants to finish the execution of a worker, the worker can either still be
-**SettingUp**, in which the main thread will wait, or the worker will be **Waiting**, in which the
-main thread will **Signal** it to complete. The worker thread changes itself to the **Running**
-state once **Signaled**. This last step exists in order to communicate back to the main thread that
-the worker thread has actually started completing its execution, rather than being preempted right
-after signalling. Once this happens, the main thread schedules the next worker. This makes sure
-there is a constant amount of workers running at one time.
-
-This activity is encapsulated in the `readyToExecute()` and `complete()` functions called by the
-worker and main thread respectively.
-
-### BufferQueueScheduler
-
-During a **BuferUpdate**, the worker thread will wait until **Signaled** to unlock and post a
-buffer that has been prefilled during the **SettingUp** phase. However if there are two sequential
-**BufferUpdates** that act on the same surface, both threads will try to lock a buffer and fill it,
-which isn't possible and will cause a deadlock. The BufferQueueScheduler solves this problem by
-handling when **BufferUpdates** should be scheduled, making sure that they don't overlap.
-
-When a surface is created, a BufferQueueScheduler is also created along side it. Whenever a
-**BufferUpdate** is read, it schedules the event onto its own internal queue and then schedules one
-every time an Event is completed.
-
-### Main
-
-The main exectuable reads in the command line arguments. Creates the Replayer using those
-arguments. Executes `replay()` on the Replayer. If there are no errors while replaying it will exit
-gracefully, if there are then it will report the error and then exit.
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
deleted file mode 100644
index d62522a..0000000
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_SURFACEREPLAYER_H
-#define ANDROID_SURFACEREPLAYER_H
-
-#include "BufferQueueScheduler.h"
-#include "Color.h"
-#include "Event.h"
-
-#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
-
-#include <gui/SurfaceComposerClient.h>
-#include <gui/SurfaceControl.h>
-
-#include <utils/Errors.h>
-#include <utils/StrongPointer.h>
-
-#include <stdatomic.h>
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-#include <queue>
-#include <thread>
-#include <unordered_map>
-#include <utility>
-
-using namespace android::surfaceflinger;
-
-namespace android {
-
-const auto DEFAULT_PATH = "/data/local/tmp/SurfaceTrace.dat";
-const auto RAND_COLOR_SEED = 700;
-const auto DEFAULT_THREADS = 3;
-
-typedef int32_t layer_id;
-typedef int32_t display_id;
-
-typedef google::protobuf::RepeatedPtrField<SurfaceChange> SurfaceChanges;
-typedef google::protobuf::RepeatedPtrField<DisplayChange> DisplayChanges;
-
-class Replayer {
- public:
- Replayer(const std::string& filename, bool replayManually = false,
- int numThreads = DEFAULT_THREADS, bool wait = true, nsecs_t stopHere = -1);
- Replayer(const Trace& trace, bool replayManually = false, int numThreads = DEFAULT_THREADS,
- bool wait = true, nsecs_t stopHere = -1);
-
- status_t replay();
-
- private:
- status_t initReplay();
-
- void waitForConsoleCommmand();
- static void stopAutoReplayHandler(int signal);
-
- status_t dispatchEvent(int index);
-
- status_t doTransaction(const Transaction& transaction, const std::shared_ptr<Event>& event);
- status_t createSurfaceControl(const SurfaceCreation& create,
- const std::shared_ptr<Event>& event);
- status_t injectVSyncEvent(const VSyncEvent& vsyncEvent, const std::shared_ptr<Event>& event);
- void createDisplay(const DisplayCreation& create, const std::shared_ptr<Event>& event);
- void deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr<Event>& event);
- void updatePowerMode(const PowerModeUpdate& update, const std::shared_ptr<Event>& event);
-
- status_t doSurfaceTransaction(SurfaceComposerClient::Transaction& transaction,
- const SurfaceChanges& surfaceChange);
- void doDisplayTransaction(SurfaceComposerClient::Transaction& transaction,
- const DisplayChanges& displayChange);
-
- void setPosition(SurfaceComposerClient::Transaction& t,
- layer_id id, const PositionChange& pc);
- void setSize(SurfaceComposerClient::Transaction& t,
- layer_id id, const SizeChange& sc);
- void setAlpha(SurfaceComposerClient::Transaction& t,
- layer_id id, const AlphaChange& ac);
- void setLayer(SurfaceComposerClient::Transaction& t,
- layer_id id, const LayerChange& lc);
- void setCrop(SurfaceComposerClient::Transaction& t,
- layer_id id, const CropChange& cc);
- void setCornerRadius(SurfaceComposerClient::Transaction& t,
- layer_id id, const CornerRadiusChange& cc);
- void setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t,
- layer_id id, const BackgroundBlurRadiusChange& cc);
- void setBlurRegions(SurfaceComposerClient::Transaction& t,
- layer_id id, const BlurRegionsChange& cc);
- void setMatrix(SurfaceComposerClient::Transaction& t,
- layer_id id, const MatrixChange& mc);
- void setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
- layer_id id, const TransparentRegionHintChange& trgc);
- void setLayerStack(SurfaceComposerClient::Transaction& t,
- layer_id id, const LayerStackChange& lsc);
- void setHiddenFlag(SurfaceComposerClient::Transaction& t,
- layer_id id, const HiddenFlagChange& hfc);
- void setOpaqueFlag(SurfaceComposerClient::Transaction& t,
- layer_id id, const OpaqueFlagChange& ofc);
- void setSecureFlag(SurfaceComposerClient::Transaction& t,
- layer_id id, const SecureFlagChange& sfc);
- void setReparentChange(SurfaceComposerClient::Transaction& t,
- layer_id id, const ReparentChange& c);
- void setRelativeParentChange(SurfaceComposerClient::Transaction& t,
- layer_id id, const RelativeParentChange& c);
- void setShadowRadiusChange(SurfaceComposerClient::Transaction& t,
- layer_id id, const ShadowRadiusChange& c);
- void setBlurRegionsChange(SurfaceComposerClient::Transaction& t,
- layer_id id, const BlurRegionsChange& c);
-
- void setDisplaySurface(SurfaceComposerClient::Transaction& t,
- display_id id, const DispSurfaceChange& dsc);
- void setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
- display_id id, const LayerStackChange& lsc);
- void setDisplaySize(SurfaceComposerClient::Transaction& t,
- display_id id, const SizeChange& sc);
- void setDisplayProjection(SurfaceComposerClient::Transaction& t,
- display_id id, const ProjectionChange& pc);
-
- void waitUntilTimestamp(int64_t timestamp);
- status_t loadSurfaceComposerClient();
-
- Trace mTrace;
- bool mLoaded = false;
- int32_t mIncrementIndex = 0;
- int64_t mCurrentTime = 0;
- int32_t mNumThreads = DEFAULT_THREADS;
-
- Increment mCurrentIncrement;
-
- std::string mLastInput;
-
- static atomic_bool sReplayingManually;
- bool mWaitingForNextVSync;
- bool mWaitForTimeStamps;
- nsecs_t mStopTimeStamp;
- bool mHasStopped;
-
- std::mutex mLayerLock;
- std::condition_variable mLayerCond;
- std::unordered_map<layer_id, sp<SurfaceControl>> mLayers;
- std::unordered_map<layer_id, HSV> mColors;
-
- std::mutex mPendingLayersLock;
- std::vector<layer_id> mLayersPendingRemoval;
-
- std::mutex mBufferQueueSchedulerLock;
- std::unordered_map<layer_id, std::shared_ptr<BufferQueueScheduler>> mBufferQueueSchedulers;
-
- std::mutex mDisplayLock;
- std::condition_variable mDisplayCond;
- std::unordered_map<display_id, sp<IBinder>> mDisplays;
-
- sp<SurfaceComposerClient> mComposerClient;
- std::queue<std::shared_ptr<Event>> mPendingIncrements;
-};
-
-} // namespace android
-#endif
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
deleted file mode 100644
index 58bfbf3..0000000
--- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
+++ /dev/null
@@ -1,285 +0,0 @@
-#!/usr/bin/python
-from subprocess import call
-import os
-proto_path = os.environ['ANDROID_BUILD_TOP'] + "/frameworks/native/cmds/surfacereplayer/proto/src/"
-call(["aprotoc", "-I=" + proto_path, "--python_out=.", proto_path + "trace.proto"])
-
-from trace_pb2 import *
-
-trace = Trace()
-
-def main():
- global trace
- while(1):
- option = main_menu()
-
- if option == 0:
- break
-
- increment = trace.increment.add()
- increment.time_stamp = int(input("Time stamp of action: "))
-
- if option == 1:
- transaction(increment)
- elif option == 2:
- surface_create(increment)
- elif option == 3:
- surface_delete(increment)
- elif option == 4:
- display_create(increment)
- elif option == 5:
- display_delete(increment)
- elif option == 6:
- buffer_update(increment)
- elif option == 7:
- vsync_event(increment)
- elif option == 8:
- power_mode_update(increment)
-
- seralizeTrace()
-
-def seralizeTrace():
- with open("trace.dat", 'wb') as f:
- f.write(trace.SerializeToString())
-
-
-def main_menu():
- print ("")
- print ("What would you like to do?")
- print ("1. Add transaction")
- print ("2. Add surface creation")
- print ("3. Add surface deletion")
- print ("4. Add display creation")
- print ("5. Add display deletion")
- print ("6. Add buffer update")
- print ("7. Add VSync event")
- print ("8. Add power mode update")
- print ("0. Finish and serialize")
- print ("")
-
- return int(input("> "))
-
-def transaction_menu():
- print ("")
- print ("What kind of transaction?")
- print ("1. Position Change")
- print ("2. Size Change")
- print ("3. Alpha Change")
- print ("4. Layer Change")
- print ("5. Crop Change")
- print ("6. Final Crop Change")
- print ("7. Matrix Change")
- print ("9. Transparent Region Hint Change")
- print ("10. Layer Stack Change")
- print ("11. Hidden Flag Change")
- print ("12. Opaque Flag Change")
- print ("13. Secure Flag Change")
- print ("14. Deferred Transaction Change")
- print ("15. Display - Surface Change")
- print ("16. Display - Layer Stack Change")
- print ("17. Display - Size Change")
- print ("18. Display - Projection Change")
- print ("0. Finished adding Changes to this transaction")
- print ("")
-
- return int(input("> "))
-
-def transaction(increment):
- global trace
-
- increment.transaction.synchronous \
- = bool(input("Is transaction synchronous (True/False): "))
- increment.transaction.animation \
- = bool(input("Is transaction animated (True/False): "))
-
- while(1):
- option = transaction_menu()
-
- if option == 0:
- break
-
- change = None
- if option <= 14:
- change = increment.transaction.surface_change.add()
- elif option >= 15 and option <= 18:
- change = increment.transaction.display_change.add()
-
- change.id = int(input("ID of layer/display to undergo a change: "))
-
- if option == 1:
- change.position.x, change.position.y = position()
- elif option == 2:
- change.size.w, change.size.h = size()
- elif option == 3:
- change.alpha.alpha = alpha()
- elif option == 4:
- change.layer.layer = layer()
- elif option == 5:
- change.crop.rectangle.left, change.crop.rectangle.top, \
- change.crop.rectangle.right, change.crop.rectangle.bottom = crop()
- elif option == 6:
- change.final_crop.rectangle.left, \
- change.final_crop.rectangle.top, \
- change.final_crop.rectangle.right,\
- change.final_crop.rectangle.bottom = final_crop()
- elif option == 7:
- change.matrix.dsdx,\
- change.matrix.dtdx,\
- change.matrix.dsdy,\
- change.matrix.dtdy = layer()
- elif option == 9:
- for rect in transparent_region_hint():
- new = increment.transparent_region_hint.region.add()
- new.left = rect[0]
- new.top = rect[1]
- new.right = rect[2]
- new.bottom = rect[3]
- elif option == 10:
- change.layer_stack.layer_stack = layer_stack()
- elif option == 11:
- change.hidden_flag.hidden_flag = hidden_flag()
- elif option == 12:
- change.opaque_flag.opaque_flag = opaque_flag()
- elif option == 13:
- change.secure_flag.secure_flag = secure_flag()
- elif option == 14:
- change.deferred_transaction.layer_id, \
- change.deferred_transaction.frame_number = deferred_transaction()
- elif option == 15:
- change.surface.buffer_queue_id, \
- change.surface.buffer_queue_name = surface()
- elif option == 16:
- change.layer_stack.layer_stack = layer_stack()
- elif option == 17:
- change.size.w, change.size.h = size()
- elif option == 18:
- projection(change)
-
-def surface_create(increment):
- increment.surface_creation.id = int(input("Enter id: "))
- n = str(raw_input("Enter name: "))
- increment.surface_creation.name = n
- increment.surface_creation.w = input("Enter w: ")
- increment.surface_creation.h = input("Enter h: ")
-
-def surface_delete(increment):
- increment.surface_deletion.id = int(input("Enter id: "))
-
-def display_create(increment):
- increment.display_creation.id = int(input("Enter id: "))
- increment.display_creation.name = str(raw_input("Enter name: "))
- increment.display_creation.display_id = int(input("Enter display ID: "))
- increment.display_creation.is_secure = bool(input("Enter if secure: "))
-
-def display_delete(increment):
- increment.surface_deletion.id = int(input("Enter id: "))
-
-def buffer_update(increment):
- increment.buffer_update.id = int(input("Enter id: "))
- increment.buffer_update.w = int(input("Enter w: "))
- increment.buffer_update.h = int(input("Enter h: "))
- increment.buffer_update.frame_number = int(input("Enter frame_number: "))
-
-def vsync_event(increment):
- increment.vsync_event.when = int(input("Enter when: "))
-
-def power_mode_update(increment):
- increment.power_mode_update.id = int(input("Enter id: "))
- increment.power_mode_update.mode = int(input("Enter mode: "))
-
-def position():
- x = input("Enter x: ")
- y = input("Enter y: ")
-
- return float(x), float(y)
-
-def size():
- w = input("Enter w: ")
- h = input("Enter h: ")
-
- return int(w), int(h)
-
-def alpha():
- alpha = input("Enter alpha: ")
-
- return float(alpha)
-
-def layer():
- layer = input("Enter layer: ")
-
- return int(layer)
-
-def crop():
- return rectangle()
-
-def final_crop():
- return rectangle()
-
-def matrix():
- dsdx = input("Enter dsdx: ")
- dtdx = input("Enter dtdx: ")
- dsdy = input("Enter dsdy: ")
- dtdy = input("Enter dtdy: ")
-
- return float(dsdx)
-
-def transparent_region_hint():
- num = input("Enter number of rectangles in region: ")
-
- return [rectangle() in range(x)]
-
-def layer_stack():
- layer_stack = input("Enter layer stack: ")
-
- return int(layer_stack)
-
-def hidden_flag():
- flag = input("Enter hidden flag state (True/False): ")
-
- return bool(flag)
-
-def opaque_flag():
- flag = input("Enter opaque flag state (True/False): ")
-
- return bool(flag)
-
-def secure_flag():
- flag = input("Enter secure flag state (True/False): ")
-
- return bool(flag)
-
-def deferred_transaction():
- layer_id = input("Enter layer_id: ")
- frame_number = input("Enter frame_number: ")
-
- return int(layer_id), int(frame_number)
-
-def surface():
- id = input("Enter id: ")
- name = raw_input("Enter name: ")
-
- return int(id), str(name)
-
-def projection(change):
- change.projection.orientation = input("Enter orientation: ")
- print("Enter rectangle for viewport")
- change.projection.viewport.left, \
- change.projection.viewport.top, \
- change.projection.viewport.right,\
- change.projection.viewport.bottom = rectangle()
- print("Enter rectangle for frame")
- change.projection.frame.left, \
- change.projection.frame.top, \
- change.projection.frame.right,\
- change.projection.frame.bottom = rectangle()
-
-def rectangle():
- left = input("Enter left: ")
- top = input("Enter top: ")
- right = input("Enter right: ")
- bottom = input("Enter bottom: ")
-
- return int(left), int(top), int(right), int(bottom)
-
-if __name__ == "__main__":
- main()
diff --git a/include/android/input.h b/include/android/input.h
index 7080386..d906af6 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -772,8 +772,17 @@
*/
AMOTION_EVENT_AXIS_GENERIC_16 = 47,
+ /**
+ * Note: This is not an "Axis constant". It does not represent any axis, nor should it be used
+ * to represent any axis. It is a constant holding the value of the largest defined axis value,
+ * to make some computations (like iterating through all possible axes) cleaner.
+ * Please update the value accordingly if you add a new axis.
+ */
+ AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GENERIC_16,
+
// NOTE: If you add a new axis here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
+ // Update AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE accordingly as well.
};
/**
diff --git a/include/android/surface_control_jni.h b/include/android/surface_control_jni.h
index 67e3a9f..a0a1fdb 100644
--- a/include/android/surface_control_jni.h
+++ b/include/android/surface_control_jni.h
@@ -36,14 +36,15 @@
/**
* Return the ASurfaceControl wrapped by a Java SurfaceControl object.
*
- * This method does not acquire any additional reference to the ASurfaceControl
- * that is returned. To keep the ASurfaceControl alive after the Java
- * SurfaceControl object is closed, explicitly or by the garbage collector, be
- * sure to use ASurfaceControl_acquire() to acquire an additional reference.
+ * The caller takes ownership of the returned ASurfaceControl returned and must
+ * release it * using ASurfaceControl_release.
+ *
+ * surfaceControlObj must be a non-null instance of android.view.SurfaceControl
+ * and isValid() must be true.
*
* Available since API level 34.
*/
-ASurfaceControl* _Nullable ASurfaceControl_fromSurfaceControl(JNIEnv* _Nonnull env,
+ASurfaceControl* _Nonnull ASurfaceControl_fromSurfaceControl(JNIEnv* _Nonnull env,
jobject _Nonnull surfaceControlObj) __INTRODUCED_IN(__ANDROID_API_U__);
/**
@@ -52,11 +53,13 @@
* The returned ASurfaceTransaction is still owned by the Java Transaction object is only
* valid while the Java Transaction object is alive. In particular, the returned transaction
* must NOT be deleted with ASurfaceTransaction_delete.
- * May return nullptr on error.
+ *
+ * transactionObj must be a non-null instance of
+ * android.view.SurfaceControl.Transaction and close() must not already be called.
*
* Available since API level 34.
*/
-ASurfaceTransaction* _Nullable ASurfaceTransaction_fromTransaction(JNIEnv* _Nonnull env,
+ASurfaceTransaction* _Nonnull ASurfaceTransaction_fromTransaction(JNIEnv* _Nonnull env,
jobject _Nonnull transactionObj) __INTRODUCED_IN(__ANDROID_API_U__);
__END_DECLS
diff --git a/include/attestation/HmacKeyManager.h b/include/attestation/HmacKeyManager.h
index 571a361..d725be1 100644
--- a/include/attestation/HmacKeyManager.h
+++ b/include/attestation/HmacKeyManager.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#ifndef ATTESTATION_HMACKEYMANAGER_H
+#define ATTESTATION_HMACKEYMANAGER_H
+
#include <array>
namespace android {
@@ -29,4 +32,6 @@
private:
const std::array<uint8_t, 128> mHmacKey;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
+
+#endif // ATTESTATION_HMACKEYMANAGER_H
\ No newline at end of file
diff --git a/include/ftl/details/match.h b/include/ftl/details/match.h
new file mode 100644
index 0000000..51b99d2
--- /dev/null
+++ b/include/ftl/details/match.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <type_traits>
+#include <variant>
+
+namespace android::ftl::details {
+
+template <typename... Ms>
+struct Matcher : Ms... {
+ using Ms::operator()...;
+};
+
+// Deduction guide.
+template <typename... Ms>
+Matcher(Ms...) -> Matcher<Ms...>;
+
+template <typename Matcher, typename... Ts>
+constexpr bool is_exhaustive_match_v = (std::is_invocable_v<Matcher, Ts> && ...);
+
+template <typename...>
+struct Match;
+
+template <typename T, typename U, typename... Ts>
+struct Match<T, U, Ts...> {
+ template <typename Variant, typename Matcher>
+ static decltype(auto) match(Variant& variant, const Matcher& matcher) {
+ if (auto* const ptr = std::get_if<T>(&variant)) {
+ return matcher(*ptr);
+ } else {
+ return Match<U, Ts...>::match(variant, matcher);
+ }
+ }
+};
+
+template <typename T>
+struct Match<T> {
+ template <typename Variant, typename Matcher>
+ static decltype(auto) match(Variant& variant, const Matcher& matcher) {
+ return matcher(std::get<T>(variant));
+ }
+};
+
+} // namespace android::ftl::details
diff --git a/include/ftl/match.h b/include/ftl/match.h
new file mode 100644
index 0000000..7318c45
--- /dev/null
+++ b/include/ftl/match.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utility>
+#include <variant>
+
+#include <ftl/details/match.h>
+
+namespace android::ftl {
+
+// Concise alternative to std::visit that compiles to branches rather than a dispatch table. For
+// std::variant<T0, ..., TN> where N is small, this is slightly faster since the branches can be
+// inlined unlike the function pointers.
+//
+// using namespace std::chrono;
+// std::variant<seconds, minutes, hours> duration = 119min;
+//
+// // Mutable match.
+// ftl::match(duration, [](auto& d) { ++d; });
+//
+// // Immutable match. Exhaustive due to minutes being convertible to seconds.
+// assert("2 hours"s ==
+// ftl::match(duration,
+// [](const seconds& s) {
+// const auto h = duration_cast<hours>(s);
+// return std::to_string(h.count()) + " hours"s;
+// },
+// [](const hours& h) { return std::to_string(h.count() / 24) + " days"s; }));
+//
+template <typename... Ts, typename... Ms>
+decltype(auto) match(std::variant<Ts...>& variant, Ms&&... matchers) {
+ const auto matcher = details::Matcher{std::forward<Ms>(matchers)...};
+ static_assert(details::is_exhaustive_match_v<decltype(matcher), Ts&...>, "Non-exhaustive match");
+
+ return details::Match<Ts...>::match(variant, matcher);
+}
+
+template <typename... Ts, typename... Ms>
+decltype(auto) match(const std::variant<Ts...>& variant, Ms&&... matchers) {
+ const auto matcher = details::Matcher{std::forward<Ms>(matchers)...};
+ static_assert(details::is_exhaustive_match_v<decltype(matcher), const Ts&...>,
+ "Non-exhaustive match");
+
+ return details::Match<Ts...>::match(variant, matcher);
+}
+
+} // namespace android::ftl
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 0026e82..f4a1523 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -280,6 +280,9 @@
std::vector<InputDeviceLightInfo> getLights();
+ inline void setSupportsUsi(bool supportsUsi) { mSupportsUsi = supportsUsi; }
+ inline bool supportsUsi() const { return mSupportsUsi; }
+
private:
int32_t mId;
int32_t mGeneration;
@@ -292,6 +295,8 @@
uint32_t mSources;
int32_t mKeyboardType;
std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
+ // Whether this device supports the Universal Stylus Initiative (USI) protocol for styluses.
+ bool mSupportsUsi;
bool mHasVibrator;
bool mHasBattery;
diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h
index ed6f6f3..e0384f3 100644
--- a/include/powermanager/PowerHalLoader.h
+++ b/include/powermanager/PowerHalLoader.h
@@ -19,6 +19,8 @@
#include <android-base/thread_annotations.h>
#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/1.2/IPower.h>
+#include <android/hardware/power/1.3/IPower.h>
#include <android/hardware/power/IPower.h>
namespace android {
@@ -32,12 +34,16 @@
static sp<hardware::power::IPower> loadAidl();
static sp<hardware::power::V1_0::IPower> loadHidlV1_0();
static sp<hardware::power::V1_1::IPower> loadHidlV1_1();
+ static sp<hardware::power::V1_2::IPower> loadHidlV1_2();
+ static sp<hardware::power::V1_3::IPower> loadHidlV1_3();
private:
static std::mutex gHalMutex;
static sp<hardware::power::IPower> gHalAidl GUARDED_BY(gHalMutex);
static sp<hardware::power::V1_0::IPower> gHalHidlV1_0 GUARDED_BY(gHalMutex);
static sp<hardware::power::V1_1::IPower> gHalHidlV1_1 GUARDED_BY(gHalMutex);
+ static sp<hardware::power::V1_2::IPower> gHalHidlV1_2 GUARDED_BY(gHalMutex);
+ static sp<hardware::power::V1_3::IPower> gHalHidlV1_3 GUARDED_BY(gHalMutex);
static sp<hardware::power::V1_0::IPower> loadHidlV1_0Locked()
EXCLUSIVE_LOCKS_REQUIRED(gHalMutex);
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index dfb0ff5..8028aa8 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -19,6 +19,8 @@
#include <android-base/thread_annotations.h>
#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/1.2/IPower.h>
+#include <android/hardware/power/1.3/IPower.h>
#include <android/hardware/power/Boost.h>
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/IPowerHintSession.h>
@@ -142,8 +144,8 @@
// Wrapper for the HIDL Power HAL v1.0.
class HidlHalWrapperV1_0 : public HalWrapper {
public:
- explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> Hal)
- : mHandleV1_0(std::move(Hal)) {}
+ explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> handleV1_0)
+ : mHandleV1_0(std::move(handleV1_0)) {}
virtual ~HidlHalWrapperV1_0() = default;
virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override;
@@ -154,10 +156,10 @@
virtual HalResult<int64_t> getHintSessionPreferredRate() override;
protected:
- virtual HalResult<void> sendPowerHint(hardware::power::V1_0::PowerHint hintId, uint32_t data);
+ const sp<hardware::power::V1_0::IPower> mHandleV1_0;
+ virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data);
private:
- sp<hardware::power::V1_0::IPower> mHandleV1_0;
HalResult<void> setInteractive(bool enabled);
HalResult<void> setFeature(hardware::power::V1_0::Feature feature, bool enabled);
};
@@ -165,17 +167,40 @@
// Wrapper for the HIDL Power HAL v1.1.
class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 {
public:
- HidlHalWrapperV1_1(sp<hardware::power::V1_0::IPower> handleV1_0,
- sp<hardware::power::V1_1::IPower> handleV1_1)
- : HidlHalWrapperV1_0(std::move(handleV1_0)), mHandleV1_1(std::move(handleV1_1)) {}
+ HidlHalWrapperV1_1(sp<hardware::power::V1_1::IPower> handleV1_1)
+ : HidlHalWrapperV1_0(std::move(handleV1_1)) {}
virtual ~HidlHalWrapperV1_1() = default;
protected:
- virtual HalResult<void> sendPowerHint(hardware::power::V1_0::PowerHint hintId,
+ virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId,
uint32_t data) override;
+};
-private:
- sp<hardware::power::V1_1::IPower> mHandleV1_1;
+// Wrapper for the HIDL Power HAL v1.2.
+class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 {
+public:
+ virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+ virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override;
+ HidlHalWrapperV1_2(sp<hardware::power::V1_2::IPower> handleV1_2)
+ : HidlHalWrapperV1_1(std::move(handleV1_2)) {}
+ virtual ~HidlHalWrapperV1_2() = default;
+
+protected:
+ virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId,
+ uint32_t data) override;
+};
+
+// Wrapper for the HIDL Power HAL v1.3.
+class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 {
+public:
+ virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override;
+ HidlHalWrapperV1_3(sp<hardware::power::V1_3::IPower> handleV1_3)
+ : HidlHalWrapperV1_2(std::move(handleV1_3)) {}
+ virtual ~HidlHalWrapperV1_3() = default;
+
+protected:
+ virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId,
+ uint32_t data) override;
};
// Wrapper for the AIDL Power HAL.
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index 15bd5c3..ebc74fb 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -23,8 +23,10 @@
#include <sys/eventfd.h>
#include <sys/uio.h>
+#include <atomic>
#include <chrono>
#include <deque>
+#include <optional>
#include <string>
#include <string_view>
#include <tuple>
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 481d704..5e725a9 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -232,7 +232,10 @@
: mRpcServer(rpcServer), mKeepAliveBinder(keepAliveBinder), mBinder(binder) {}
virtual ~RpcServerLink();
void binderDied(const wp<IBinder>&) override {
- LOG_RPC_DETAIL("RpcServerLink: binder died, shutting down RpcServer");
+ auto promoted = mBinder.promote();
+ ALOGI("RpcBinder: binder died, shutting down RpcServer for %s",
+ promoted ? String8(promoted->getInterfaceDescriptor()).c_str() : "<NULL>");
+
if (mRpcServer == nullptr) {
ALOGW("RpcServerLink: Unable to shut down RpcServer because it does not exist.");
} else {
@@ -241,11 +244,7 @@
}
mRpcServer.clear();
- auto promoted = mBinder.promote();
- if (promoted == nullptr) {
- ALOGW("RpcServerLink: Unable to remove link from parent binder object because parent "
- "binder object is gone.");
- } else {
+ if (promoted) {
promoted->removeRpcServerLink(sp<RpcServerLink>::fromExisting(this));
}
mBinder.clear();
@@ -706,6 +705,7 @@
return status;
}
rpcServer->setMaxThreads(binderThreadPoolMaxCount);
+ LOG(INFO) << "RpcBinder: Started Binder debug on " << getInterfaceDescriptor();
rpcServer->start();
e->mRpcServerLinks.emplace(link);
LOG_RPC_DETAIL("%s(fd=%d) successful", __PRETTY_FUNCTION__, socketFdForPrint);
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index bfcf39a..11c8e5d 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -39,7 +39,6 @@
#include <sys/resource.h>
#include <unistd.h>
-#include "Static.h"
#include "binder_module.h"
#if LOG_NDEBUG
@@ -124,46 +123,43 @@
return "unknown";
}
-static const void* printBinderTransactionData(TextOutput& out, const void* data)
-{
+static const void* printBinderTransactionData(std::ostream& out, const void* data) {
const binder_transaction_data* btd =
(const binder_transaction_data*)data;
if (btd->target.handle < 1024) {
/* want to print descriptors in decimal; guess based on value */
- out << "target.desc=" << btd->target.handle;
+ out << "\ttarget.desc=" << btd->target.handle;
} else {
- out << "target.ptr=" << btd->target.ptr;
+ out << "\ttarget.ptr=" << btd->target.ptr;
}
- out << " (cookie " << btd->cookie << ")" << endl
- << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(uint64_t)btd->flags << endl
- << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
- << " bytes)" << endl
- << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
- << " bytes)";
+ out << "\t (cookie " << btd->cookie << ")"
+ << "\n"
+ << "\tcode=" << TypeCode(btd->code) << ", flags=" << (void*)(uint64_t)btd->flags << "\n"
+ << "\tdata=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)"
+ << "\n"
+ << "\toffsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size << " bytes)";
return btd+1;
}
-static const void* printReturnCommand(TextOutput& out, const void* _cmd)
-{
+static const void* printReturnCommand(std::ostream& out, const void* _cmd) {
static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
uint32_t code = (uint32_t)*cmd++;
size_t cmdIndex = code & 0xff;
if (code == BR_ERROR) {
- out << "BR_ERROR: " << (void*)(uint64_t)(*cmd++) << endl;
+ out << "\tBR_ERROR: " << (void*)(uint64_t)(*cmd++) << "\n";
return cmd;
} else if (cmdIndex >= N) {
- out << "Unknown reply: " << code << endl;
+ out << "\tUnknown reply: " << code << "\n";
return cmd;
}
- out << kReturnStrings[cmdIndex];
+ out << "\t" << kReturnStrings[cmdIndex];
switch (code) {
case BR_TRANSACTION:
case BR_REPLY: {
- out << ": " << indent;
- cmd = (const int32_t *)printBinderTransactionData(out, cmd);
- out << dedent;
+ out << ": ";
+ cmd = (const int32_t*)printBinderTransactionData(out, cmd);
} break;
case BR_ACQUIRE_RESULT: {
@@ -200,19 +196,18 @@
break;
}
- out << endl;
+ out << "\n";
return cmd;
}
-static const void* printCommand(TextOutput& out, const void* _cmd)
-{
+static const void* printCommand(std::ostream& out, const void* _cmd) {
static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
uint32_t code = (uint32_t)*cmd++;
size_t cmdIndex = code & 0xff;
if (cmdIndex >= N) {
- out << "Unknown command: " << code << endl;
+ out << "Unknown command: " << code << "\n";
return cmd;
}
out << kCommandStrings[cmdIndex];
@@ -220,9 +215,8 @@
switch (code) {
case BC_TRANSACTION:
case BC_REPLY: {
- out << ": " << indent;
- cmd = (const int32_t *)printBinderTransactionData(out, cmd);
- out << dedent;
+ out << ": ";
+ cmd = (const int32_t*)printBinderTransactionData(out, cmd);
} break;
case BC_ACQUIRE_RESULT: {
@@ -274,7 +268,7 @@
break;
}
- out << endl;
+ out << "\n";
return cmd;
}
@@ -548,8 +542,10 @@
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
- alog << "Processing top-level Command: "
- << getReturnString(cmd) << endl;
+ std::ostringstream logStream;
+ logStream << "Processing top-level Command: " << getReturnString(cmd) << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
pthread_mutex_lock(&mProcess->mThreadCountLock);
@@ -726,10 +722,11 @@
flags |= TF_ACCEPT_FDS;
IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
- << handle << " / code " << TypeCode(code) << ": "
- << indent << data << dedent << endl;
+ std::ostringstream logStream;
+ logStream << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand " << handle
+ << " / code " << TypeCode(code) << ": \t" << data << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
@@ -774,11 +771,15 @@
#endif
IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
- << handle << ": ";
- if (reply) alog << indent << *reply << dedent << endl;
- else alog << "(none requested)" << endl;
+ std::ostringstream logStream;
+ logStream << "BR_REPLY thr " << (void*)pthread_self() << " / hand " << handle << ": ";
+ if (reply)
+ logStream << "\t" << *reply << "\n";
+ else
+ logStream << "(none requested)"
+ << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
} else {
err = waitForResponse(nullptr, nullptr);
@@ -920,8 +921,10 @@
cmd = (uint32_t)mIn.readInt32();
IF_LOG_COMMANDS() {
- alog << "Processing waitForResponse Command: "
- << getReturnString(cmd) << endl;
+ std::ostringstream logStream;
+ logStream << "Processing waitForResponse Command: " << getReturnString(cmd) << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
switch (cmd) {
@@ -1033,17 +1036,19 @@
}
IF_LOG_COMMANDS() {
- TextOutput::Bundle _b(alog);
+ std::ostringstream logStream;
if (outAvail != 0) {
- alog << "Sending commands to driver: " << indent;
+ logStream << "Sending commands to driver: ";
const void* cmds = (const void*)bwr.write_buffer;
- const void* end = ((const uint8_t*)cmds)+bwr.write_size;
- alog << HexDump(cmds, bwr.write_size) << endl;
- while (cmds < end) cmds = printCommand(alog, cmds);
- alog << dedent;
+ const void* end = ((const uint8_t*)cmds) + bwr.write_size;
+ logStream << "\t" << HexDump(cmds, bwr.write_size) << "\n";
+ while (cmds < end) cmds = printCommand(logStream, cmds);
}
- alog << "Size of receive buffer: " << bwr.read_size
- << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
+ logStream << "Size of receive buffer: " << bwr.read_size << ", needRead: " << needRead
+ << ", doReceive: " << doReceive << "\n";
+
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
// Return immediately if there is nothing to do.
@@ -1054,7 +1059,10 @@
status_t err;
do {
IF_LOG_COMMANDS() {
- alog << "About to read/write, write size = " << mOut.dataSize() << endl;
+ std::ostringstream logStream;
+ logStream << "About to read/write, write size = " << mOut.dataSize() << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
@@ -1068,14 +1076,20 @@
err = -EBADF;
}
IF_LOG_COMMANDS() {
- alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
+ std::ostringstream logStream;
+ logStream << "Finished read/write, write size = " << mOut.dataSize() << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
} while (err == -EINTR);
IF_LOG_COMMANDS() {
- alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
- << bwr.write_consumed << " (of " << mOut.dataSize()
- << "), read consumed: " << bwr.read_consumed << endl;
+ std::ostringstream logStream;
+ logStream << "Our err: " << (void*)(intptr_t)err
+ << ", write consumed: " << bwr.write_consumed << " (of " << mOut.dataSize()
+ << "), read consumed: " << bwr.read_consumed << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
if (err >= NO_ERROR) {
@@ -1096,14 +1110,15 @@
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
- TextOutput::Bundle _b(alog);
- alog << "Remaining data size: " << mOut.dataSize() << endl;
- alog << "Received commands from driver: " << indent;
+ std::ostringstream logStream;
+ logStream << "Remaining data size: " << mOut.dataSize() << "\n";
+ logStream << "Received commands from driver: ";
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
- alog << HexDump(cmds, mIn.dataSize()) << endl;
- while (cmds < end) cmds = printReturnCommand(alog, cmds);
- alog << dedent;
+ logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n";
+ while (cmds < end) cmds = printReturnCommand(logStream, cmds);
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
return NO_ERROR;
}
@@ -1285,15 +1300,15 @@
Parcel reply;
status_t error;
IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_TRANSACTION thr " << (void*)pthread_self()
- << " / obj " << tr.target.ptr << " / code "
- << TypeCode(tr.code) << ": " << indent << buffer
- << dedent << endl
- << "Data addr = "
- << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
- << ", offsets addr="
- << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
+ std::ostringstream logStream;
+ logStream << "BR_TRANSACTION thr " << (void*)pthread_self() << " / obj "
+ << tr.target.ptr << " / code " << TypeCode(tr.code) << ": \t" << buffer
+ << "\n"
+ << "Data addr = " << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
+ << ", offsets addr="
+ << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
@@ -1329,21 +1344,21 @@
sendReply(reply, (tr.flags & kForwardReplyFlags));
} else {
if (error != OK) {
- alog << "oneway function results for code " << tr.code
- << " on binder at "
- << reinterpret_cast<void*>(tr.target.ptr)
- << " will be dropped but finished with status "
- << statusToString(error);
+ std::ostringstream logStream;
+ logStream << "oneway function results for code " << tr.code << " on binder at "
+ << reinterpret_cast<void*>(tr.target.ptr)
+ << " will be dropped but finished with status "
+ << statusToString(error);
// ideally we could log this even when error == OK, but it
// causes too much logspam because some manually-written
// interfaces have clients that call methods which always
// write results, sometimes as oneway methods.
if (reply.dataSize() != 0) {
- alog << " and reply parcel size " << reply.dataSize();
+ logStream << " and reply parcel size " << reply.dataSize();
}
-
- alog << endl;
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
@@ -1358,9 +1373,11 @@
mPropagateWorkSource = origPropagateWorkSet;
IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
- << tr.target.ptr << ": " << indent << reply << dedent << endl;
+ std::ostringstream logStream;
+ logStream << "BC_REPLY thr " << (void*)pthread_self() << " / obj " << tr.target.ptr
+ << ": \t" << reply << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
}
@@ -1481,7 +1498,10 @@
const binder_size_t* /*objects*/, size_t /*objectsSize*/) {
//ALOGI("Freeing parcel %p", &parcel);
IF_LOG_COMMANDS() {
- alog << "Writing BC_FREE_BUFFER for " << data << endl;
+ std::ostringstream logStream;
+ logStream << "Writing BC_FREE_BUFFER for " << data << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
ALOG_ASSERT(data != NULL, "Called with NULL data");
IPCThreadState* state = self();
diff --git a/libs/binder/OS.cpp b/libs/binder/OS.cpp
index 24ce2bb..77e401f 100644
--- a/libs/binder/OS.cpp
+++ b/libs/binder/OS.cpp
@@ -18,6 +18,7 @@
#include <android-base/file.h>
#include <binder/RpcTransportRaw.h>
+#include <log/log.h>
#include <string.h>
using android::base::ErrnoError;
@@ -25,6 +26,9 @@
namespace android {
+// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets.
+constexpr size_t kMaxFdsPerMsg = 253;
+
Result<void> setNonBlocking(android::base::borrowed_fd fd) {
int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
if (flags == -1) {
@@ -63,4 +67,99 @@
return RpcTransportCtxFactoryRaw::make();
}
+int sendMessageOnSocket(
+ const RpcTransportFd& socket, iovec* iovs, int niovs,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
+ if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
+ if (ancillaryFds->size() > kMaxFdsPerMsg) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then
+ // use memcpy.
+ int fds[kMaxFdsPerMsg];
+ for (size_t i = 0; i < ancillaryFds->size(); i++) {
+ fds[i] = std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i));
+ }
+ const size_t fdsByteSize = sizeof(int) * ancillaryFds->size();
+
+ alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)];
+
+ msghdr msg{
+ .msg_iov = iovs,
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ .msg_control = msgControlBuf,
+ .msg_controllen = sizeof(msgControlBuf),
+ };
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(fdsByteSize);
+ memcpy(CMSG_DATA(cmsg), fds, fdsByteSize);
+
+ msg.msg_controllen = CMSG_SPACE(fdsByteSize);
+ return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
+ }
+
+ msghdr msg{
+ .msg_iov = iovs,
+ // posix uses int, glibc uses size_t. niovs is a
+ // non-negative int and can be cast to either.
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ };
+ return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL));
+}
+
+int receiveMessageFromSocket(
+ const RpcTransportFd& socket, iovec* iovs, int niovs,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
+ if (ancillaryFds != nullptr) {
+ int fdBuffer[kMaxFdsPerMsg];
+ alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))];
+
+ msghdr msg{
+ .msg_iov = iovs,
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ .msg_control = msgControlBuf,
+ .msg_controllen = sizeof(msgControlBuf),
+ };
+ ssize_t processSize = TEMP_FAILURE_RETRY(recvmsg(socket.fd.get(), &msg, MSG_NOSIGNAL));
+ if (processSize < 0) {
+ return -1;
+ }
+
+ for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks
+ // application devs to memcpy the data to ensure memory alignment.
+ size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0);
+ LOG_ALWAYS_FATAL_IF(dataLen > sizeof(fdBuffer)); // validity check
+ memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen);
+ size_t fdCount = dataLen / sizeof(int);
+ ancillaryFds->reserve(ancillaryFds->size() + fdCount);
+ for (size_t i = 0; i < fdCount; i++) {
+ ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i]));
+ }
+ break;
+ }
+ }
+
+ if (msg.msg_flags & MSG_CTRUNC) {
+ errno = EPIPE;
+ return -1;
+ }
+ return processSize;
+ }
+ msghdr msg{
+ .msg_iov = iovs,
+ // posix uses int, glibc uses size_t. niovs is a
+ // non-negative int and can be cast to either.
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ };
+
+ return TEMP_FAILURE_RETRY(recvmsg(socket.fd.get(), &msg, MSG_NOSIGNAL));
+}
+
} // namespace android
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index 5ab8bab..0d38968 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -33,4 +33,12 @@
std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory();
+int sendMessageOnSocket(
+ const RpcTransportFd& socket, iovec* iovs, int niovs,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds);
+
+int receiveMessageFromSocket(
+ const RpcTransportFd& socket, iovec* iovs, int niovs,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds);
+
} // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 8887572..07d0a65 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1439,7 +1439,8 @@
case RpcSession::FileDescriptorTransportMode::NONE: {
return FDS_NOT_ALLOWED;
}
- case RpcSession::FileDescriptorTransportMode::UNIX: {
+ case RpcSession::FileDescriptorTransportMode::UNIX:
+ case RpcSession::FileDescriptorTransportMode::TRUSTY: {
if (rpcFields->mFds == nullptr) {
rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
}
@@ -2639,8 +2640,7 @@
return OK;
}
-void Parcel::print(TextOutput& to, uint32_t /*flags*/) const
-{
+void Parcel::print(std::ostream& to, uint32_t /*flags*/) const {
to << "Parcel(";
if (errorCheck() != NO_ERROR) {
@@ -2648,7 +2648,7 @@
to << "Error: " << (void*)(intptr_t)err << " \"" << strerror(-err) << "\"";
} else if (dataSize() > 0) {
const uint8_t* DATA = data();
- to << indent << HexDump(DATA, dataSize()) << dedent;
+ to << "\t" << HexDump(DATA, dataSize());
#ifdef BINDER_WITH_KERNEL_IPC
if (const auto* kernelFields = maybeKernelFields()) {
const binder_size_t* OBJS = kernelFields->mObjects;
@@ -2656,8 +2656,7 @@
for (size_t i = 0; i < N; i++) {
const flat_binder_object* flat =
reinterpret_cast<const flat_binder_object*>(DATA + OBJS[i]);
- to << endl
- << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
+ to << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
<< TypeCode(flat->hdr.type & 0x7f7f7f00) << " = " << flat->binder;
}
}
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index e581d0b..83d0de7 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -37,6 +37,7 @@
#include "OS.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
+#include "RpcTransportUtils.h"
#include "RpcWireFormat.h"
#include "Utils.h"
@@ -61,6 +62,10 @@
return sp<RpcServer>::make(std::move(ctx));
}
+status_t RpcServer::setupUnixDomainSocketBootstrapServer(unique_fd bootstrapFd) {
+ return setupExternalServer(std::move(bootstrapFd), &RpcServer::recvmsgSocketConnection);
+}
+
status_t RpcServer::setupUnixDomainServer(const char* path) {
return setupSocketServer(UnixSocketAddress(path));
}
@@ -177,11 +182,50 @@
rpcJoinIfSingleThreaded(*mJoinThread);
}
+status_t RpcServer::acceptSocketConnection(const RpcServer& server, RpcTransportFd* out) {
+ RpcTransportFd clientSocket(unique_fd(TEMP_FAILURE_RETRY(
+ accept4(server.mServer.fd.get(), nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK))));
+ if (clientSocket.fd < 0) {
+ int savedErrno = errno;
+ ALOGE("Could not accept4 socket: %s", strerror(savedErrno));
+ return -savedErrno;
+ }
+
+ *out = std::move(clientSocket);
+ return OK;
+}
+
+status_t RpcServer::recvmsgSocketConnection(const RpcServer& server, RpcTransportFd* out) {
+ int zero = 0;
+ iovec iov{&zero, sizeof(zero)};
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds;
+
+ if (receiveMessageFromSocket(server.mServer, &iov, 1, &fds) < 0) {
+ int savedErrno = errno;
+ ALOGE("Failed recvmsg: %s", strerror(savedErrno));
+ return -savedErrno;
+ }
+ if (fds.size() != 1) {
+ ALOGE("Expected exactly one fd from recvmsg, got %zu", fds.size());
+ return -EINVAL;
+ }
+
+ unique_fd fd(std::move(std::get<unique_fd>(fds.back())));
+ if (auto res = setNonBlocking(fd); !res.ok()) {
+ ALOGE("Failed setNonBlocking: %s", res.error().message().c_str());
+ return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code();
+ }
+
+ *out = RpcTransportFd(std::move(fd));
+ return OK;
+}
+
void RpcServer::join() {
{
RpcMutexLockGuard _l(mLock);
LOG_ALWAYS_FATAL_IF(!mServer.fd.ok(), "RpcServer must be setup to join.");
+ LOG_ALWAYS_FATAL_IF(mAcceptFn == nullptr, "RpcServer must have an accept() function");
LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
mJoinThreadRunning = true;
mShutdownTrigger = FdTrigger::make();
@@ -192,20 +236,19 @@
while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
std::array<uint8_t, kRpcAddressSize> addr;
static_assert(addr.size() >= sizeof(sockaddr_storage), "kRpcAddressSize is too small");
-
socklen_t addrLen = addr.size();
- RpcTransportFd clientSocket(unique_fd(TEMP_FAILURE_RETRY(
- accept4(mServer.fd.get(), reinterpret_cast<sockaddr*>(addr.data()), &addrLen,
- SOCK_CLOEXEC | SOCK_NONBLOCK))));
- LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(sockaddr_storage)),
- "Truncated address");
-
- if (clientSocket.fd < 0) {
- ALOGE("Could not accept4 socket: %s", strerror(errno));
+ RpcTransportFd clientSocket;
+ if (mAcceptFn(*this, &clientSocket) != OK) {
continue;
}
- LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());
+ if (getpeername(clientSocket.fd.get(), reinterpret_cast<sockaddr*>(addr.data()),
+ &addrLen)) {
+ ALOGE("Could not getpeername socket: %s", strerror(errno));
+ continue;
+ }
+
+ LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());
{
RpcMutexLockGuard _l(mLock);
@@ -550,16 +593,23 @@
return std::move(mServer.fd);
}
-status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
+status_t RpcServer::setupExternalServer(
+ base::unique_fd serverFd,
+ std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn) {
RpcMutexLockGuard _l(mLock);
if (mServer.fd.ok()) {
ALOGE("Each RpcServer can only have one server.");
return INVALID_OPERATION;
}
mServer = std::move(serverFd);
+ mAcceptFn = std::move(acceptFn);
return OK;
}
+status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
+ return setupExternalServer(std::move(serverFd), &RpcServer::acceptSocketConnection);
+}
+
bool RpcServer::hasActiveRequests() {
RpcMutexLockGuard _l(mLock);
for (const auto& [_, session] : mSessions) {
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 49843e5..7d6bcfc 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -41,6 +41,7 @@
#include "OS.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
+#include "RpcTransportUtils.h"
#include "RpcWireFormat.h"
#include "Utils.h"
@@ -147,6 +148,34 @@
return setupSocketClient(UnixSocketAddress(path));
}
+status_t RpcSession::setupUnixDomainSocketBootstrapClient(unique_fd bootstrapFd) {
+ mBootstrapTransport =
+ mCtx->newTransport(RpcTransportFd(std::move(bootstrapFd)), mShutdownTrigger.get());
+ return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) {
+ int socks[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, socks) < 0) {
+ int savedErrno = errno;
+ ALOGE("Failed socketpair: %s", strerror(savedErrno));
+ return -savedErrno;
+ }
+ unique_fd clientFd(socks[0]), serverFd(socks[1]);
+
+ int zero = 0;
+ iovec iov{&zero, sizeof(zero)};
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds;
+ fds.push_back(std::move(serverFd));
+
+ status_t status = mBootstrapTransport->interruptableWriteFully(mShutdownTrigger.get(), &iov,
+ 1, std::nullopt, &fds);
+ if (status != OK) {
+ ALOGE("Failed to send fd over bootstrap transport: %s", strerror(-status));
+ return status;
+ }
+
+ return initAndAddConnection(RpcTransportFd(std::move(clientFd)), sessionId, incoming);
+ });
+}
+
status_t RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
return setupSocketClient(VsockSocketAddress(cid, port));
}
@@ -295,16 +324,18 @@
}
void RpcSession::WaitForShutdownListener::onSessionIncomingThreadEnded() {
+ mShutdownCount += 1;
mCv.notify_all();
}
void RpcSession::WaitForShutdownListener::waitForShutdown(RpcMutexUniqueLock& lock,
const sp<RpcSession>& session) {
- while (session->mConnections.mIncoming.size() > 0) {
+ while (mShutdownCount < session->mConnections.mMaxIncoming) {
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->mConnections.mIncoming.size());
+ "still %zu/%zu fully shutdown.",
+ session->mConnections.mIncoming.size(), mShutdownCount.load(),
+ session->mConnections.mMaxIncoming);
}
}
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index c0e36c4..b27f102 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -41,7 +41,7 @@
#if RPC_FLAKE_PRONE
void rpcMaybeWaitToFlake() {
[[clang::no_destroy]] static std::random_device r;
- [[clang::no_destroy]] static std::mutex m;
+ [[clang::no_destroy]] static RpcMutex m;
unsigned num;
{
RpcMutexLockGuard lock(m);
@@ -56,6 +56,7 @@
case RpcSession::FileDescriptorTransportMode::NONE:
return false;
case RpcSession::FileDescriptorTransportMode::UNIX:
+ case RpcSession::FileDescriptorTransportMode::TRUSTY:
return true;
}
}
@@ -886,6 +887,7 @@
it->second.asyncTodo.push(BinderNode::AsyncTodo{
.ref = target,
.data = std::move(transactionData),
+ .ancillaryFds = std::move(ancillaryFds),
.asyncNumber = transaction->asyncNumber,
});
@@ -1046,6 +1048,7 @@
// reset up arguments
transactionData = std::move(todo.data);
+ ancillaryFds = std::move(todo.ancillaryFds);
LOG_ALWAYS_FATAL_IF(target != todo.ref,
"async list should be associated with a binder");
@@ -1205,6 +1208,20 @@
rpcFields->mFds->size(), kMaxFdsPerMsg);
return BAD_VALUE;
}
+ break;
+ }
+ case RpcSession::FileDescriptorTransportMode::TRUSTY: {
+ // Keep this in sync with trusty_ipc.h!!!
+ // We could import that file here on Trusty, but it's not
+ // available on Android
+ constexpr size_t kMaxFdsPerMsg = 8;
+ if (rpcFields->mFds->size() > kMaxFdsPerMsg) {
+ *errorMsg = StringPrintf("Too many file descriptors in Parcel for Trusty "
+ "IPC connection: %zu (max is %zu)",
+ rpcFields->mFds->size(), kMaxFdsPerMsg);
+ return BAD_VALUE;
+ }
+ break;
}
}
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 7aab5ee..ac86585 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -250,6 +250,7 @@
struct AsyncTodo {
sp<IBinder> ref;
CommandData data;
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds;
uint64_t asyncNumber = 0;
bool operator<(const AsyncTodo& o) const {
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 65e8fac..1912d14 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -23,6 +23,7 @@
#include <binder/RpcTransportRaw.h>
#include "FdTrigger.h"
+#include "OS.h"
#include "RpcState.h"
#include "RpcTransportUtils.h"
@@ -30,9 +31,6 @@
namespace {
-// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets.
-constexpr size_t kMaxFdsPerMsg = 253;
-
// RpcTransport with TLS disabled.
class RpcTransportRaw : public RpcTransport {
public:
@@ -63,57 +61,9 @@
override {
bool sentFds = false;
auto send = [&](iovec* iovs, int niovs) -> ssize_t {
- if (ancillaryFds != nullptr && !ancillaryFds->empty() && !sentFds) {
- if (ancillaryFds->size() > kMaxFdsPerMsg) {
- // This shouldn't happen because we check the FD count in RpcState.
- ALOGE("Saw too many file descriptors in RpcTransportCtxRaw: %zu (max is %zu). "
- "Aborting session.",
- ancillaryFds->size(), kMaxFdsPerMsg);
- errno = EINVAL;
- return -1;
- }
-
- // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then
- // use memcpy.
- int fds[kMaxFdsPerMsg];
- for (size_t i = 0; i < ancillaryFds->size(); i++) {
- fds[i] = std::visit([](const auto& fd) { return fd.get(); },
- ancillaryFds->at(i));
- }
- const size_t fdsByteSize = sizeof(int) * ancillaryFds->size();
-
- alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)];
-
- msghdr msg{
- .msg_iov = iovs,
- .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
- .msg_control = msgControlBuf,
- .msg_controllen = sizeof(msgControlBuf),
- };
-
- cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(fdsByteSize);
- memcpy(CMSG_DATA(cmsg), fds, fdsByteSize);
-
- msg.msg_controllen = CMSG_SPACE(fdsByteSize);
-
- ssize_t processedSize = TEMP_FAILURE_RETRY(
- sendmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
- if (processedSize > 0) {
- sentFds = true;
- }
- return processedSize;
- }
-
- msghdr msg{
- .msg_iov = iovs,
- // posix uses int, glibc uses size_t. niovs is a
- // non-negative int and can be cast to either.
- .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
- };
- return TEMP_FAILURE_RETRY(sendmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL));
+ int ret = sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds);
+ sentFds |= ret > 0;
+ return ret;
};
return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT,
altPoll);
@@ -124,54 +74,7 @@
const std::optional<android::base::function_ref<status_t()>>& altPoll,
std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
auto recv = [&](iovec* iovs, int niovs) -> ssize_t {
- if (ancillaryFds != nullptr) {
- int fdBuffer[kMaxFdsPerMsg];
- alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))];
-
- msghdr msg{
- .msg_iov = iovs,
- .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
- .msg_control = msgControlBuf,
- .msg_controllen = sizeof(msgControlBuf),
- };
- ssize_t processSize =
- TEMP_FAILURE_RETRY(recvmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL));
- if (processSize < 0) {
- return -1;
- }
-
- for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks
- // application devs to memcpy the data to ensure memory alignment.
- size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0);
- LOG_ALWAYS_FATAL_IF(dataLen > sizeof(fdBuffer)); // sanity check
- memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen);
- size_t fdCount = dataLen / sizeof(int);
- ancillaryFds->reserve(ancillaryFds->size() + fdCount);
- for (size_t i = 0; i < fdCount; i++) {
- ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i]));
- }
- break;
- }
- }
-
- if (msg.msg_flags & MSG_CTRUNC) {
- ALOGE("msg was truncated. Aborting session.");
- errno = EPIPE;
- return -1;
- }
-
- return processSize;
- }
- msghdr msg{
- .msg_iov = iovs,
- // posix uses int, glibc uses size_t. niovs is a
- // non-negative int and can be cast to either.
- .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
- };
- return TEMP_FAILURE_RETRY(recvmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL));
+ return receiveMessageFromSocket(mSocket, iovs, niovs, ancillaryFds);
};
return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN,
altPoll);
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index c91d56c..342e4a3 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -58,13 +58,10 @@
"name": "CtsOsTestCases",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "include-filter": "android.os.cts.BinderTest"
},
{
- "exclude-filter": "android.os.cts.BuildTest#testSdkInt"
- },
- {
- "exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage"
+ "include-filter": "android.os.cts.ParcelTest"
}
]
},
diff --git a/libs/binder/TextOutput.cpp b/libs/binder/TextOutput.cpp
index a0ade50..5dd1f90 100644
--- a/libs/binder/TextOutput.cpp
+++ b/libs/binder/TextOutput.cpp
@@ -39,11 +39,10 @@
static void textOutputPrinter(void* cookie, const char* txt)
{
- ((TextOutput*)cookie)->print(txt, strlen(txt));
+ ((std::ostream*)cookie)->write(txt, strlen(txt));
}
-TextOutput& operator<<(TextOutput& to, const TypeCode& val)
-{
+std::ostream& operator<<(std::ostream& to, const TypeCode& val) {
printTypeCode(val.typeCode(), textOutputPrinter, (void*)&to);
return to;
}
@@ -61,8 +60,7 @@
else mAlignment = 1;
}
-TextOutput& operator<<(TextOutput& to, const HexDump& val)
-{
+std::ostream& operator<<(std::ostream& to, const HexDump& val) {
printHexData(0, val.buffer(), val.size(), val.bytesPerLine(),
val.singleLineCutoff(), val.alignment(), val.carrayStyle(),
textOutputPrinter, (void*)&to);
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 5469239..6de6ce8 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -595,7 +595,7 @@
// uid.
uid_t readCallingWorkSourceUid() const;
- void print(TextOutput& to, uint32_t flags = 0) const;
+ void print(std::ostream& to, uint32_t flags = 0) const;
private:
// `objects` and `objectsSize` always 0 for RPC Parcels.
@@ -1594,8 +1594,7 @@
// ---------------------------------------------------------------------------
-inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
-{
+inline std::ostream& operator<<(std::ostream& to, const Parcel& parcel) {
parcel.print(to);
return to;
}
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 2c99334..81ae26a3 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -50,6 +50,17 @@
std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
/**
+ * Creates an RPC server that bootstraps sessions using an existing
+ * Unix domain socket pair.
+ *
+ * Callers should create a pair of SOCK_STREAM Unix domain sockets, pass
+ * one to RpcServer::setupUnixDomainSocketBootstrapServer and the other
+ * to RpcSession::setupUnixDomainSocketBootstrapClient. Multiple client
+ * session can be created from the client end of the pair.
+ */
+ [[nodiscard]] status_t setupUnixDomainSocketBootstrapServer(base::unique_fd serverFd);
+
+ /**
* This represents a session for responses, e.g.:
*
* process A serves binder a
@@ -202,11 +213,18 @@
void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
+ status_t setupExternalServer(
+ base::unique_fd serverFd,
+ std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn);
+
static constexpr size_t kRpcAddressSize = 128;
static void establishConnection(
sp<RpcServer>&& server, RpcTransportFd clientFd,
std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen,
std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn);
+ static status_t acceptSocketConnection(const RpcServer& server, RpcTransportFd* out);
+ static status_t recvmsgSocketConnection(const RpcServer& server, RpcTransportFd* out);
+
[[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
const std::unique_ptr<RpcTransportCtx> mCtx;
@@ -228,6 +246,7 @@
std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
std::unique_ptr<FdTrigger> mShutdownTrigger;
RpcConditionVariable mShutdownCv;
+ std::function<status_t(const RpcServer& server, RpcTransportFd* out)> mAcceptFn;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index a25ba98..40faf2c 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -100,6 +100,8 @@
NONE = 0,
// Send file descriptors via unix domain socket ancillary data.
UNIX = 1,
+ // Send file descriptors as Trusty IPC handles.
+ TRUSTY = 2,
};
/**
@@ -115,6 +117,11 @@
[[nodiscard]] status_t setupUnixDomainClient(const char* path);
/**
+ * Connects to an RPC server over a nameless Unix domain socket pair.
+ */
+ [[nodiscard]] status_t setupUnixDomainSocketBootstrapClient(base::unique_fd bootstrap);
+
+ /**
* Connects to an RPC server at the CVD & port.
*/
[[nodiscard]] status_t setupVsockClient(unsigned int cvd, unsigned int port);
@@ -233,6 +240,7 @@
private:
RpcConditionVariable mCv;
+ std::atomic<size_t> mShutdownCount = 0;
};
friend WaitForShutdownListener;
@@ -366,11 +374,14 @@
RpcConditionVariable mAvailableConnectionCv; // for mWaitingThreads
+ std::unique_ptr<RpcTransport> mBootstrapTransport;
+
struct ThreadState {
size_t mWaitingThreads = 0;
// hint index into clients, ++ when sending an async transaction
size_t mOutgoingOffset = 0;
std::vector<sp<RpcConnection>> mOutgoing;
+ // max size of mIncoming. Once any thread starts down, no more can be started.
size_t mMaxIncoming = 0;
std::vector<sp<RpcConnection>> mIncoming;
std::map<RpcMaybeThread::id, RpcMaybeThread> mThreads;
diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h
index bf9c92b..eb98042 100644
--- a/libs/binder/include/binder/TextOutput.h
+++ b/libs/binder/include/binder/TextOutput.h
@@ -94,7 +94,7 @@
uint32_t mCode;
};
-TextOutput& operator<<(TextOutput& to, const TypeCode& val);
+std::ostream& operator<<(std::ostream& to, const TypeCode& val);
class HexDump
{
@@ -123,7 +123,7 @@
bool mCArrayStyle;
};
-TextOutput& operator<<(TextOutput& to, const HexDump& val);
+std::ostream& operator<<(std::ostream& to, const HexDump& val);
inline TextOutput& operator<<(TextOutput& to,
decltype(std::endl<char,
std::char_traits<char>>)
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 7ea9be7..fccc0af 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -349,7 +349,7 @@
/**
* See AIBinder_Weak_promote.
*/
- SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
+ SpAIBinder promote() const { return SpAIBinder(AIBinder_Weak_promote(get())); }
};
namespace internal {
diff --git a/libs/binder/ndk/include_platform/android/binder_libbinder.h b/libs/binder/ndk/include_platform/android/binder_libbinder.h
index dfe12a1..74a7157 100644
--- a/libs/binder/ndk/include_platform/android/binder_libbinder.h
+++ b/libs/binder/ndk/include_platform/android/binder_libbinder.h
@@ -16,7 +16,7 @@
#pragma once
-#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
+#if (!defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)) || defined(__TRUSTY__)
#include <android/binder_ibinder.h>
#include <android/binder_parcel.h>
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 6d29238..01b9472 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -670,6 +670,26 @@
EXPECT_EQ(42, pparcel->readInt32());
}
+TEST(NdkBinder, GetAndVerifyScopedAIBinder_Weak) {
+ for (const ndk::SpAIBinder& binder :
+ {// remote
+ ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)),
+ // local
+ ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) {
+ // get a const ScopedAIBinder_Weak and verify promote
+ EXPECT_NE(binder.get(), nullptr);
+ const ndk::ScopedAIBinder_Weak wkAIBinder =
+ ndk::ScopedAIBinder_Weak(AIBinder_Weak_new(binder.get()));
+ EXPECT_EQ(wkAIBinder.promote().get(), binder.get());
+ // get another ScopedAIBinder_Weak and verify
+ ndk::ScopedAIBinder_Weak wkAIBinder2 =
+ ndk::ScopedAIBinder_Weak(AIBinder_Weak_new(binder.get()));
+ EXPECT_FALSE(AIBinder_Weak_lt(wkAIBinder.get(), wkAIBinder2.get()));
+ EXPECT_FALSE(AIBinder_Weak_lt(wkAIBinder2.get(), wkAIBinder.get()));
+ EXPECT_EQ(wkAIBinder2.promote(), wkAIBinder.promote());
+ }
+}
+
class MyResultReceiver : public BnResultReceiver {
public:
Mutex mMutex;
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 63c8684..976f54d 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -1091,7 +1091,7 @@
}
} => {
$( #[$attr] )*
- #[derive(Debug, Default, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
+ #[derive(Default, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub struct $enum(pub $backing);
impl $enum {
@@ -1104,6 +1104,15 @@
}
}
+ impl std::fmt::Debug for $enum {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self.0 {
+ $($value => f.write_str(stringify!($name)),)*
+ _ => f.write_fmt(format_args!("{}", self.0))
+ }
+ }
+ }
+
impl $crate::binder_impl::Serialize for $enum {
fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
parcel.write(&self.0)
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
index 34d74be..4cdeac4 100644
--- a/libs/binder/tests/BinderRpcTestServerConfig.aidl
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -21,5 +21,6 @@
int rpcSecurity;
int serverVersion;
int vsockPort;
+ int unixBootstrapFd; // Inherited from parent
@utf8InCpp String addr;
}
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index b15a225..a3ed571 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -71,4 +71,13 @@
ParcelFileDescriptor echoAsFile(@utf8InCpp String content);
ParcelFileDescriptor concatFiles(in List<ParcelFileDescriptor> files);
+
+ // FDs sent via `blockingSendFdOneway` can be received via
+ // `blockingRecvFd`. The handler for `blockingSendFdOneway` will block
+ // until the next `blockingRecvFd` call.
+ //
+ // This is useful for carefully controlling how/when oneway transactions
+ // get queued.
+ oneway void blockingSendFdOneway(in ParcelFileDescriptor fd);
+ ParcelFileDescriptor blockingRecvFd();
}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 6e1c8ac..25b524f 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -115,6 +115,7 @@
BINDER_LIB_TEST_NOP_TRANSACTION_WAIT,
BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_ECHO_VECTOR,
+ BINDER_LIB_TEST_GET_NON_BLOCKING_FD,
BINDER_LIB_TEST_REJECT_OBJECTS,
BINDER_LIB_TEST_CAN_GET_SID,
BINDER_LIB_TEST_GET_MAX_THREAD_COUNT,
@@ -1158,6 +1159,21 @@
EXPECT_EQ(readValue, testValue);
}
+TEST_F(BinderLibTest, FileDescriptorRemainsNonBlocking) {
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+
+ Parcel reply;
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_NON_BLOCKING_FD, {} /*data*/, &reply),
+ StatusEq(NO_ERROR));
+ base::unique_fd fd;
+ EXPECT_THAT(reply.readUniqueFileDescriptor(&fd), StatusEq(OK));
+
+ const int result = fcntl(fd.get(), F_GETFL);
+ ASSERT_NE(result, -1);
+ EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
+}
+
// see ProcessState.cpp BINDER_VM_SIZE = 1MB.
// This value is not exposed, but some code in the framework relies on being able to use
// buffers near the cap size.
@@ -1801,6 +1817,28 @@
reply->writeUint64Vector(vector);
return NO_ERROR;
}
+ case BINDER_LIB_TEST_GET_NON_BLOCKING_FD: {
+ std::array<int, 2> sockets;
+ const bool created = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets.data()) == 0;
+ if (!created) {
+ ALOGE("Could not create socket pair");
+ return UNKNOWN_ERROR;
+ }
+
+ const int result = fcntl(sockets[0], F_SETFL, O_NONBLOCK);
+ if (result != 0) {
+ ALOGE("Could not make socket non-blocking: %s", strerror(errno));
+ return UNKNOWN_ERROR;
+ }
+ base::unique_fd out(sockets[0]);
+ status_t writeResult = reply->writeUniqueFileDescriptor(out);
+ if (writeResult != NO_ERROR) {
+ ALOGE("Could not write unique_fd");
+ return writeResult;
+ }
+ close(sockets[1]); // we don't need the other side of the fd
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_REJECT_OBJECTS: {
return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR;
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 21b0354..7294305 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -85,6 +85,11 @@
return base::StringPrintf("unexpected state %d", wstatus);
}
+static void debugBacktrace(pid_t pid) {
+ std::cerr << "TAKING BACKTRACE FOR PID " << pid << std::endl;
+ system((std::string("debuggerd -b ") + std::to_string(pid)).c_str());
+}
+
class Process {
public:
Process(Process&&) = default;
@@ -125,6 +130,8 @@
// Kill the process. Avoid if possible. Shutdown gracefully via an RPC instead.
void terminate() { kill(mPid, SIGTERM); }
+ pid_t getPid() { return mPid; }
+
private:
std::function<void(int wstatus)> mCustomExitStatusCheck;
pid_t mPid = 0;
@@ -173,7 +180,21 @@
wp<RpcSession> weakSession = session;
session = nullptr;
- EXPECT_EQ(nullptr, weakSession.promote()) << "Leaked session";
+
+ // b/244325464 - 'getStrongCount' is printing '1' on failure here, which indicates the
+ // the object should not actually be promotable. By looping, we distinguish a race here
+ // from a bug causing the object to not be promotable.
+ for (size_t i = 0; i < 3; i++) {
+ sp<RpcSession> strongSession = weakSession.promote();
+ EXPECT_EQ(nullptr, strongSession)
+ << (debugBacktrace(host.getPid()), debugBacktrace(getpid()),
+ "Leaked sess: ")
+ << strongSession->getStrongCount() << " checked time " << i;
+
+ if (strongSession != nullptr) {
+ sleep(1);
+ }
+ }
}
}
};
@@ -233,6 +254,25 @@
return serverFd;
}
+static base::unique_fd connectToUnixBootstrap(const RpcTransportFd& transportFd) {
+ base::unique_fd sockClient, sockServer;
+ if (!base::Socketpair(SOCK_STREAM, &sockClient, &sockServer)) {
+ int savedErrno = errno;
+ LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
+ }
+
+ int zero = 0;
+ iovec iov{&zero, sizeof(zero)};
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds;
+ fds.emplace_back(std::move(sockServer));
+
+ if (sendMessageOnSocket(transportFd, &iov, 1, &fds) < 0) {
+ int savedErrno = errno;
+ LOG(FATAL) << "Failed sendMessageOnSocket: " << strerror(savedErrno);
+ }
+ return std::move(sockClient);
+}
+
using RunServiceFn = void (*)(android::base::borrowed_fd writeEnd,
android::base::borrowed_fd readEnd);
@@ -253,7 +293,14 @@
// Whether the test params support sending FDs in parcels.
bool supportsFdTransport() const {
return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
- (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX);
+ (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
+ socketType() == SocketType::UNIX_BOOTSTRAP);
+ }
+
+ void SetUp() override {
+ if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) {
+ GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport";
+ }
}
static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
@@ -287,6 +334,14 @@
singleThreaded ? "_single_threaded" : "",
noKernel ? "_no_kernel" : "");
+ base::unique_fd bootstrapClientFd, bootstrapServerFd;
+ // Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec.
+ // This is because we cannot pass ParcelFileDescriptor over a pipe.
+ if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) {
+ int savedErrno = errno;
+ LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
+ }
+
auto ret = ProcessSession{
.host = Process([=](android::base::borrowed_fd writeEnd,
android::base::borrowed_fd readEnd) {
@@ -304,6 +359,7 @@
serverConfig.serverVersion = serverVersion;
serverConfig.vsockPort = allocateVsockPort();
serverConfig.addr = allocateSocketAddress();
+ serverConfig.unixBootstrapFd = bootstrapServerFd.get();
for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
static_cast<int32_t>(mode));
@@ -353,6 +409,10 @@
case SocketType::UNIX:
status = session->setupUnixDomainClient(serverConfig.addr.c_str());
break;
+ case SocketType::UNIX_BOOTSTRAP:
+ status = session->setupUnixDomainSocketBootstrapClient(
+ base::unique_fd(dup(bootstrapClientFd.get())));
+ break;
case SocketType::VSOCK:
status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
break;
@@ -419,7 +479,8 @@
}
SocketType type = std::get<0>(GetParam());
- if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) {
+ if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
+ type == SocketType::UNIX_BOOTSTRAP) {
// we can't get port numbers for unix sockets
return;
}
@@ -777,12 +838,12 @@
ts.push_back(std::thread([&] { proc.rootIface->lockUnlock(); }));
}
- usleep(100000); // give chance for calls on other threads
+ usleep(10000); // give chance for calls on other threads
// other calls still work
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
- constexpr size_t blockTimeMs = 500;
+ constexpr size_t blockTimeMs = 50;
size_t epochMsBefore = epochMillis();
// after this, we should never see a response within this time
EXPECT_OK(proc.rootIface->unlockInMsAsync(blockTimeMs));
@@ -911,6 +972,45 @@
EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
}
+TEST_P(BinderRpc, OnewayCallQueueingWithFds) {
+ if (!supportsFdTransport()) {
+ GTEST_SKIP() << "Would fail trivially (which is tested elsewhere)";
+ }
+ if (clientOrServerSingleThreaded()) {
+ GTEST_SKIP() << "This test requires multiple threads";
+ }
+
+ // This test forces a oneway transaction to be queued by issuing two
+ // `blockingSendFdOneway` calls, then drains the queue by issuing two
+ // `blockingRecvFd` calls.
+ //
+ // For more details about the queuing semantics see
+ // https://developer.android.com/reference/android/os/IBinder#FLAG_ONEWAY
+
+ auto proc = createRpcTestSocketServerProcess({
+ .numThreads = 3,
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ EXPECT_OK(proc.rootIface->blockingSendFdOneway(
+ android::os::ParcelFileDescriptor(mockFileDescriptor("a"))));
+ EXPECT_OK(proc.rootIface->blockingSendFdOneway(
+ android::os::ParcelFileDescriptor(mockFileDescriptor("b"))));
+
+ android::os::ParcelFileDescriptor fdA;
+ EXPECT_OK(proc.rootIface->blockingRecvFd(&fdA));
+ std::string result;
+ CHECK(android::base::ReadFdToString(fdA.get(), &result));
+ EXPECT_EQ(result, "a");
+
+ android::os::ParcelFileDescriptor fdB;
+ EXPECT_OK(proc.rootIface->blockingRecvFd(&fdB));
+ CHECK(android::base::ReadFdToString(fdB.get(), &result));
+ EXPECT_EQ(result, "b");
+}
+
TEST_P(BinderRpc, OnewayCallQueueing) {
if (clientOrServerSingleThreaded()) {
GTEST_SKIP() << "This test requires multiple threads";
@@ -1074,7 +1174,7 @@
}
std::unique_lock<std::mutex> lock(dr->mMtx);
- ASSERT_TRUE(dr->mCv.wait_for(lock, 1000ms, [&]() { return dr->dead; }));
+ ASSERT_TRUE(dr->mCv.wait_for(lock, 100ms, [&]() { return dr->dead; }));
// need to wait for the session to shutdown so we don't "Leak session"
EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
@@ -1109,7 +1209,7 @@
std::unique_lock<std::mutex> lock(dr->mMtx);
if (!dr->dead) {
- EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 1000ms));
+ EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 100ms));
}
EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
@@ -1516,7 +1616,7 @@
}
static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
- std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
+ std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET};
if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
@@ -1692,7 +1792,7 @@
bool shutdown = false;
for (int i = 0; i < 10 && !shutdown; i++) {
- usleep(300 * 1000); // 300ms; total 3s
+ usleep(30 * 1000); // 30ms; total 300ms
if (server->shutdown()) shutdown = true;
}
ASSERT_TRUE(shutdown) << "server->shutdown() never returns true";
@@ -1717,6 +1817,8 @@
// A server that handles client socket connections.
class Server {
public:
+ using AcceptConnection = std::function<base::unique_fd(Server*)>;
+
explicit Server() {}
Server(Server&&) = default;
~Server() { shutdownAndWait(); }
@@ -1741,6 +1843,21 @@
return connectTo(UnixSocketAddress(addr.c_str()));
};
} break;
+ case SocketType::UNIX_BOOTSTRAP: {
+ base::unique_fd bootstrapFdClient, bootstrapFdServer;
+ if (!base::Socketpair(SOCK_STREAM, &bootstrapFdClient, &bootstrapFdServer)) {
+ return AssertionFailure() << "Socketpair() failed";
+ }
+ auto status = rpcServer->setupUnixDomainSocketBootstrapServer(
+ std::move(bootstrapFdServer));
+ if (status != OK) {
+ return AssertionFailure() << "setupUnixDomainSocketBootstrapServer: "
+ << statusToString(status);
+ }
+ mBootstrapSocket = RpcTransportFd(std::move(bootstrapFdClient));
+ mAcceptConnection = &Server::recvmsgServerConnection;
+ mConnectToServer = [this] { return connectToUnixBootstrap(mBootstrapSocket); };
+ } break;
case SocketType::VSOCK: {
auto port = allocateVsockPort();
auto status = rpcServer->setupVsockServer(port);
@@ -1788,14 +1905,33 @@
LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
mThread = std::make_unique<std::thread>(&Server::run, this);
}
+
+ base::unique_fd acceptServerConnection() {
+ return base::unique_fd(TEMP_FAILURE_RETRY(
+ accept4(mFd.fd.get(), nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK)));
+ }
+
+ base::unique_fd recvmsgServerConnection() {
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds;
+ int buf;
+ iovec iov{&buf, sizeof(buf)};
+
+ if (receiveMessageFromSocket(mFd, &iov, 1, &fds) < 0) {
+ int savedErrno = errno;
+ LOG(FATAL) << "Failed receiveMessage: " << strerror(savedErrno);
+ }
+ if (fds.size() != 1) {
+ LOG(FATAL) << "Expected one FD from receiveMessage(), got " << fds.size();
+ }
+ return std::move(std::get<base::unique_fd>(fds[0]));
+ }
+
void run() {
LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
std::vector<std::thread> threads;
while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) {
- base::unique_fd acceptedFd(
- TEMP_FAILURE_RETRY(accept4(mFd.fd.get(), nullptr, nullptr /*length*/,
- SOCK_CLOEXEC | SOCK_NONBLOCK)));
+ base::unique_fd acceptedFd = mAcceptConnection(this);
threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd));
}
@@ -1822,8 +1958,9 @@
private:
std::unique_ptr<std::thread> mThread;
ConnectToServer mConnectToServer;
+ AcceptConnection mAcceptConnection = &Server::acceptServerConnection;
std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
- RpcTransportFd mFd;
+ RpcTransportFd mFd, mBootstrapSocket;
std::unique_ptr<RpcTransportCtx> mCtx;
std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
std::make_shared<RpcCertificateVerifierSimple>();
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index 4513d36..823bbf6 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -49,6 +49,7 @@
#include "../BuildFlags.h"
#include "../FdTrigger.h"
+#include "../OS.h" // for testing UnixBootstrap clients
#include "../RpcSocketAddress.h" // for testing preconnected clients
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
@@ -67,15 +68,19 @@
enum class SocketType {
PRECONNECTED,
UNIX,
+ UNIX_BOOTSTRAP,
VSOCK,
INET,
};
+
static inline std::string PrintToString(SocketType socketType) {
switch (socketType) {
case SocketType::PRECONNECTED:
return "preconnected_uds";
case SocketType::UNIX:
return "unix_domain_socket";
+ case SocketType::UNIX_BOOTSTRAP:
+ return "unix_domain_socket_bootstrap";
case SocketType::VSOCK:
return "vm_socket";
case SocketType::INET:
@@ -167,6 +172,42 @@
return readFd;
}
+// A threadsafe channel where writes block until the value is read.
+template <typename T>
+class HandoffChannel {
+public:
+ void write(T v) {
+ {
+ RpcMutexUniqueLock lock(mMutex);
+ // Wait for space to send.
+ mCvEmpty.wait(lock, [&]() { return !mValue.has_value(); });
+ mValue.emplace(std::move(v));
+ }
+ mCvFull.notify_all();
+ RpcMutexUniqueLock lock(mMutex);
+ // Wait for it to be taken.
+ mCvEmpty.wait(lock, [&]() { return !mValue.has_value(); });
+ }
+
+ T read() {
+ RpcMutexUniqueLock lock(mMutex);
+ if (!mValue.has_value()) {
+ mCvFull.wait(lock, [&]() { return mValue.has_value(); });
+ }
+ T v = std::move(mValue.value());
+ mValue.reset();
+ lock.unlock();
+ mCvEmpty.notify_all();
+ return std::move(v);
+ }
+
+private:
+ RpcMutex mMutex;
+ RpcConditionVariable mCvEmpty;
+ RpcConditionVariable mCvFull;
+ std::optional<T> mValue;
+};
+
using android::binder::Status;
class MyBinderRpcSession : public BnBinderRpcSession {
@@ -374,6 +415,18 @@
out->reset(mockFileDescriptor(acc));
return Status::ok();
}
+
+ HandoffChannel<android::base::unique_fd> mFdChannel;
+
+ Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& fd) override {
+ mFdChannel.write(android::base::unique_fd(fcntl(fd.get(), F_DUPFD_CLOEXEC, 0)));
+ return Status::ok();
+ }
+
+ Status blockingRecvFd(android::os::ParcelFileDescriptor* fd) override {
+ fd->reset(mFdChannel.read());
+ return Status::ok();
+ }
};
} // namespace android
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
index 31eb5da..a922b21 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -42,6 +42,7 @@
server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes);
unsigned int outPort = 0;
+ base::unique_fd unixBootstrapFd(serverConfig.unixBootstrapFd);
switch (socketType) {
case SocketType::PRECONNECTED:
@@ -50,6 +51,9 @@
CHECK_EQ(OK, server->setupUnixDomainServer(serverConfig.addr.c_str()))
<< serverConfig.addr;
break;
+ case SocketType::UNIX_BOOTSTRAP:
+ CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(unixBootstrapFd)));
+ break;
case SocketType::VSOCK:
CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
break;
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 0210237..3904e1d 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -84,6 +84,7 @@
},
},
srcs: [
+ "random_binder.cpp",
"random_fd.cpp",
"random_parcel.cpp",
"libbinder_driver.cpp",
diff --git a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h
similarity index 63%
copy from libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
copy to libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h
index 9fac3e8..8fc9263 100644
--- a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,16 @@
* limitations under the License.
*/
-package android.gui;
+#pragma once
-/** @hide */
-parcelable MirrorSurfaceResult {
- IBinder handle;
- int layerId;
-}
+#include <binder/IBinder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+// Get a random binder object for use in fuzzing.
+//
+// May return nullptr.
+sp<IBinder> getRandomBinder(FuzzedDataProvider* provider);
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_binder.cpp b/libs/binder/tests/parcel_fuzzer/random_binder.cpp
new file mode 100644
index 0000000..8a1fecb
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/random_binder.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/random_binder.h>
+
+#include <fuzzbinder/random_parcel.h>
+
+#include <android-base/logging.h>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+class RandomBinder : public BBinder {
+public:
+ RandomBinder(const String16& descriptor, std::vector<uint8_t>&& bytes)
+ : mDescriptor(descriptor),
+ mBytes(std::move(bytes)),
+ mProvider(mBytes.data(), mBytes.size()) {}
+ const String16& getInterfaceDescriptor() const override { return mDescriptor; }
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override {
+ (void)code;
+ (void)data;
+ (void)reply;
+ (void)flags; // note - for maximum coverage even ignore if oneway
+
+ if (mProvider.ConsumeBool()) {
+ return mProvider.ConsumeIntegral<status_t>();
+ }
+
+ if (reply == nullptr) return OK;
+
+ // TODO: things we could do to increase state space
+ // - also pull FDs and binders from 'data'
+ // (optionally combine these into random parcel 'options')
+ // - also pull FDs and binders from random parcel 'options'
+ RandomParcelOptions options;
+
+ // random output
+ std::vector<uint8_t> subData = mProvider.ConsumeBytes<uint8_t>(
+ mProvider.ConsumeIntegralInRange<size_t>(0, mProvider.remaining_bytes()));
+ fillRandomParcel(reply, FuzzedDataProvider(subData.data(), subData.size()), &options);
+
+ return OK;
+ }
+
+private:
+ String16 mDescriptor;
+
+ // note may not all be used
+ std::vector<uint8_t> mBytes;
+ FuzzedDataProvider mProvider;
+};
+
+sp<IBinder> getRandomBinder(FuzzedDataProvider* provider) {
+ auto makeFunc = provider->PickValueInArray<const std::function<sp<IBinder>()>>({
+ [&]() {
+ // descriptor is the length of a class name, e.g.
+ // "some.package.Foo"
+ std::string str = provider->ConsumeRandomLengthString(100 /*max length*/);
+
+ // arbitrarily consume remaining data to create a binder that can return
+ // random results - coverage guided fuzzer should ensure all of the remaining
+ // data isn't always used
+ std::vector<uint8_t> bytes = provider->ConsumeBytes<uint8_t>(
+ provider->ConsumeIntegralInRange<size_t>(0, provider->remaining_bytes()));
+
+ return new RandomBinder(String16(str.c_str()), std::move(bytes));
+ },
+ []() {
+ // this is the easiest remote binder to get ahold of, and it
+ // should be able to handle anything thrown at it, and
+ // essentially every process can talk to it, so it's a good
+ // candidate for checking usage of an actual BpBinder
+ return IInterface::asBinder(defaultServiceManager());
+ },
+ [&]() -> sp<IBinder> { return nullptr; },
+ });
+ return makeFunc();
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 51cb768..edc695f 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -17,23 +17,14 @@
#include <fuzzbinder/random_parcel.h>
#include <android-base/logging.h>
-#include <binder/IServiceManager.h>
#include <binder/RpcSession.h>
#include <binder/RpcTransportRaw.h>
+#include <fuzzbinder/random_binder.h>
#include <fuzzbinder/random_fd.h>
#include <utils/String16.h>
namespace android {
-class NamedBinder : public BBinder {
-public:
- NamedBinder(const String16& descriptor) : mDescriptor(descriptor) {}
- const String16& getInterfaceDescriptor() const override { return mDescriptor; }
-
-private:
- String16 mDescriptor;
-};
-
static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) {
std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes());
CHECK(OK == p->write(data.data(), data.size()));
@@ -45,6 +36,11 @@
if (provider.ConsumeBool()) {
auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
CHECK_EQ(OK, session->addNullDebuggingClient());
+ // Set the protocol version so that we don't crash if the session
+ // actually gets used. This isn't cheating because the version should
+ // always be set if the session init succeeded and we aren't testing the
+ // session init here (it is bypassed by addNullDebuggingClient).
+ session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION);
p->markForRpc(session);
if (options->writeHeader) {
@@ -89,32 +85,16 @@
},
// write binder
[&]() {
- auto makeFunc = provider.PickValueInArray<const std::function<sp<IBinder>()>>({
- [&]() {
- // descriptor is the length of a class name, e.g.
- // "some.package.Foo"
- std::string str =
- provider.ConsumeRandomLengthString(100 /*max length*/);
- return new NamedBinder(String16(str.c_str()));
- },
- []() {
- // this is the easiest remote binder to get ahold of, and it
- // should be able to handle anything thrown at it, and
- // essentially every process can talk to it, so it's a good
- // candidate for checking usage of an actual BpBinder
- return IInterface::asBinder(defaultServiceManager());
- },
- [&]() -> sp<IBinder> {
- if (options->extraBinders.size() > 0 && provider.ConsumeBool()) {
- return options->extraBinders.at(
- provider.ConsumeIntegralInRange<
- size_t>(0, options->extraBinders.size() - 1));
- } else {
- return nullptr;
- }
- },
- });
- sp<IBinder> binder = makeFunc();
+ sp<IBinder> binder;
+ if (options->extraBinders.size() > 0 && provider.ConsumeBool()) {
+ binder = options->extraBinders.at(
+ provider.ConsumeIntegralInRange<size_t>(0,
+ options->extraBinders
+ .size() -
+ 1));
+ } else {
+ binder = getRandomBinder(&provider);
+ }
CHECK(OK == p->writeStrongBinder(binder));
},
});
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index 46346bb..397ff41 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -16,6 +16,7 @@
#if defined(TRUSTY_USERSPACE)
#include <openssl/rand.h>
+#include <trusty_ipc.h>
#else
#include <lib/rand/rand.h>
#endif
@@ -23,6 +24,7 @@
#include <binder/RpcTransportTipcTrusty.h>
#include "../OS.h"
+#include "TrustyStatus.h"
using android::base::Result;
@@ -43,13 +45,32 @@
#endif // TRUSTY_USERSPACE
}
-status_t dupFileDescriptor(int /*oldFd*/, int* /*newFd*/) {
- // TODO: implement separately
- return INVALID_OPERATION;
+status_t dupFileDescriptor(int oldFd, int* newFd) {
+ int res = dup(oldFd);
+ if (res < 0) {
+ return statusFromTrusty(res);
+ }
+
+ *newFd = res;
+ return OK;
}
std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() {
return RpcTransportCtxFactoryTipcTrusty::make();
}
+int sendMessageOnSocket(
+ const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) {
+ errno = ENOTSUP;
+ return -1;
+}
+
+int receiveMessageFromSocket(
+ const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) {
+ errno = ENOTSUP;
+ return -1;
+}
+
} // namespace android
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
index 0b67b9f..58bfe71 100644
--- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "RpcTransportTipcTrusty"
+#include <inttypes.h>
#include <trusty_ipc.h>
#include <binder/RpcSession.h>
@@ -47,7 +48,7 @@
status_t interruptableWriteFully(
FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
- const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
override {
if (niovs < 0) {
return BAD_VALUE;
@@ -58,12 +59,32 @@
size += iovs[i].iov_len;
}
+ handle_t msgHandles[IPC_MAX_MSG_HANDLES];
ipc_msg_t msg{
.num_iov = static_cast<uint32_t>(niovs),
.iov = iovs,
- .num_handles = 0, // TODO: add ancillaryFds
+ .num_handles = 0,
.handles = nullptr,
};
+
+ if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
+ if (ancillaryFds->size() > IPC_MAX_MSG_HANDLES) {
+ // This shouldn't happen because we check the FD count in RpcState.
+ ALOGE("Saw too many file descriptors in RpcTransportCtxTipcTrusty: "
+ "%zu (max is %u). Aborting session.",
+ ancillaryFds->size(), IPC_MAX_MSG_HANDLES);
+ return BAD_VALUE;
+ }
+
+ for (size_t i = 0; i < ancillaryFds->size(); i++) {
+ msgHandles[i] =
+ std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i));
+ }
+
+ msg.num_handles = ancillaryFds->size();
+ msg.handles = msgHandles;
+ }
+
ssize_t rc = send_msg(mSocket.fd.get(), &msg);
if (rc == ERR_NOT_ENOUGH_BUFFER) {
// Peer is blocked, wait until it unblocks.
@@ -97,8 +118,7 @@
status_t interruptableReadFully(
FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
- std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
- override {
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
if (niovs < 0) {
return BAD_VALUE;
}
@@ -124,11 +144,16 @@
return status;
}
+ LOG_ALWAYS_FATAL_IF(mMessageInfo.num_handles > IPC_MAX_MSG_HANDLES,
+ "Received too many handles %" PRIu32, mMessageInfo.num_handles);
+ bool haveHandles = mMessageInfo.num_handles != 0;
+ handle_t msgHandles[IPC_MAX_MSG_HANDLES];
+
ipc_msg_t msg{
.num_iov = static_cast<uint32_t>(niovs),
.iov = iovs,
- .num_handles = 0, // TODO: support ancillaryFds
- .handles = nullptr,
+ .num_handles = mMessageInfo.num_handles,
+ .handles = haveHandles ? msgHandles : 0,
};
ssize_t rc = read_msg(mSocket.fd.get(), mMessageInfo.id, mMessageOffset, &msg);
if (rc < 0) {
@@ -141,6 +166,28 @@
"Message offset exceeds length %zu/%zu", mMessageOffset,
mMessageInfo.len);
+ if (haveHandles) {
+ if (ancillaryFds != nullptr) {
+ ancillaryFds->reserve(ancillaryFds->size() + mMessageInfo.num_handles);
+ for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
+ ancillaryFds->emplace_back(base::unique_fd(msgHandles[i]));
+ }
+
+ // Clear the saved number of handles so we don't accidentally
+ // read them multiple times
+ mMessageInfo.num_handles = 0;
+ haveHandles = false;
+ } else {
+ ALOGE("Received unexpected handles %" PRIu32, mMessageInfo.num_handles);
+ // It should be safe to continue here. We could abort, but then
+ // peers could DoS us by sending messages with handles in them.
+ // Close the handles since we are ignoring them.
+ for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
+ ::close(msgHandles[i]);
+ }
+ }
+ }
+
// Release the message if all of it has been read
if (mMessageOffset == mMessageInfo.len) {
releaseMessage();
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index cc31c95..7d9dd8c 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -60,6 +60,10 @@
std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); }
+ void setSupportedFileDescriptorTransportModes(
+ const std::vector<RpcSession::FileDescriptorTransportMode>& modes) {
+ mRpcServer->setSupportedFileDescriptorTransportModes(modes);
+ }
void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); }
void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); }
void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) {
diff --git a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl b/libs/binder/trusty/ndk/include/sys/cdefs.h
similarity index 66%
copy from libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
copy to libs/binder/trusty/ndk/include/sys/cdefs.h
index 9fac3e8..6a48d2b 100644
--- a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
+++ b/libs/binder/trusty/ndk/include/sys/cdefs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
-package android.gui;
+#include <lk/compiler.h>
-/** @hide */
-parcelable MirrorSurfaceResult {
- IBinder handle;
- int layerId;
-}
+/* Alias the bionic macros to the ones from lk/compiler.h */
+#define __BEGIN_DECLS __BEGIN_CDECLS
+#define __END_DECLS __END_CDECLS
+
+#define __INTRODUCED_IN(x) /* nothing on Trusty */
diff --git a/libs/binder/trusty/ndk/rules.mk b/libs/binder/trusty/ndk/rules.mk
new file mode 100644
index 0000000..03fd006
--- /dev/null
+++ b/libs/binder/trusty/ndk/rules.mk
@@ -0,0 +1,38 @@
+# 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+LIBBINDER_NDK_DIR := frameworks/native/libs/binder/ndk
+
+MODULE_SRCS := \
+ $(LIBBINDER_NDK_DIR)/ibinder.cpp \
+ $(LIBBINDER_NDK_DIR)/libbinder.cpp \
+ $(LIBBINDER_NDK_DIR)/parcel.cpp \
+ $(LIBBINDER_NDK_DIR)/status.cpp \
+
+MODULE_EXPORT_INCLUDES += \
+ $(LOCAL_DIR)/include \
+ $(LIBBINDER_NDK_DIR)/include_cpp \
+ $(LIBBINDER_NDK_DIR)/include_ndk \
+ $(LIBBINDER_NDK_DIR)/include_platform \
+
+MODULE_LIBRARY_DEPS += \
+ trusty/user/base/lib/libstdc++-trusty \
+ frameworks/native/libs/binder/trusty \
+
+include make/library.mk
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index a25a493..c1945fd 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -21,6 +21,7 @@
"fake_guard_test.cpp",
"flags_test.cpp",
"future_test.cpp",
+ "match_test.cpp",
"optional_test.cpp",
"small_map_test.cpp",
"small_vector_test.cpp",
diff --git a/libs/ftl/match_test.cpp b/libs/ftl/match_test.cpp
new file mode 100644
index 0000000..a6cff2e
--- /dev/null
+++ b/libs/ftl/match_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ftl/match.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <string>
+#include <variant>
+
+namespace android::test {
+
+// Keep in sync with example usage in header file.
+TEST(Match, Example) {
+ using namespace std::chrono;
+ using namespace std::chrono_literals;
+ using namespace std::string_literals;
+
+ std::variant<seconds, minutes, hours> duration = 119min;
+
+ // Mutable match.
+ ftl::match(duration, [](auto& d) { ++d; });
+
+ // Immutable match. Exhaustive due to minutes being convertible to seconds.
+ EXPECT_EQ("2 hours"s,
+ ftl::match(
+ duration,
+ [](const seconds& s) {
+ const auto h = duration_cast<hours>(s);
+ return std::to_string(h.count()) + " hours"s;
+ },
+ [](const hours& h) { return std::to_string(h.count() / 24) + " days"s; }));
+}
+
+} // namespace android::test
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index d3144bb..23a2181 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -217,7 +217,6 @@
"SurfaceControl.cpp",
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
- "TransactionTracing.cpp",
"VsyncEventData.cpp",
"view/Surface.cpp",
"WindowInfosListenerReporter.cpp",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 3afa339..8b9a878 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -307,7 +307,6 @@
BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
"empty.");
}
-
decStrong((void*)transactionCommittedCallbackThunk);
}
}
@@ -350,6 +349,20 @@
stat.latchTime,
stat.frameEventStats.dequeueReadyTime);
}
+ auto currFrameNumber = stat.frameEventStats.frameNumber;
+ std::vector<ReleaseCallbackId> staleReleases;
+ for (const auto& [key, value]: mSubmitted) {
+ if (currFrameNumber > key.framenumber) {
+ staleReleases.push_back(key);
+ }
+ }
+ for (const auto& staleRelease : staleReleases) {
+ BQA_LOGE("Faking releaseBufferCallback from transactionCompleteCallback");
+ BBQ_TRACE("FakeReleaseCallback");
+ releaseBufferCallbackLocked(staleRelease,
+ stat.previousReleaseFence ? stat.previousReleaseFence : Fence::NO_FENCE,
+ stat.currentMaxAcquiredBufferCount);
+ }
} else {
BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
}
@@ -390,7 +403,14 @@
const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount) {
BBQ_TRACE();
+
std::unique_lock _lock{mMutex};
+ releaseBufferCallbackLocked(id, releaseFence, currentMaxAcquiredBufferCount);
+}
+
+void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id,
+ const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) {
+ ATRACE_CALL();
BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
// Calculate how many buffers we need to hold before we release them back
@@ -408,7 +428,11 @@
const auto numPendingBuffersToHold =
isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0;
- mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence});
+
+ auto rb = ReleasedBuffer{id, releaseFence};
+ if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) {
+ mPendingRelease.emplace_back(rb);
+ }
// Release all buffers that are beyond the ones that we need to hold
while (mPendingRelease.size() > numPendingBuffersToHold) {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index af64b3b..4c887ec 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -19,7 +19,6 @@
#include <android/gui/IDisplayEventConnection.h>
#include <android/gui/IRegionSamplingListener.h>
-#include <android/gui/ITransactionTraceListener.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 4d5978c..924e65e 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -40,13 +40,13 @@
x(0),
y(0),
z(0),
- alpha(0),
flags(0),
mask(0),
reserved(0),
cornerRadius(0.0f),
backgroundBlurRadius(0),
- transform(0),
+ color(0),
+ bufferTransform(0),
transformToDisplayInverse(false),
crop(Rect::INVALID_RECT),
dataspace(ui::Dataspace::UNKNOWN),
@@ -83,20 +83,19 @@
SAFE_PARCEL(output.writeFloat, y);
SAFE_PARCEL(output.writeInt32, z);
SAFE_PARCEL(output.writeUint32, layerStack.id);
- SAFE_PARCEL(output.writeFloat, alpha);
SAFE_PARCEL(output.writeUint32, flags);
SAFE_PARCEL(output.writeUint32, mask);
SAFE_PARCEL(matrix.write, output);
SAFE_PARCEL(output.write, crop);
- SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild);
SAFE_PARCEL(output.writeFloat, color.r);
SAFE_PARCEL(output.writeFloat, color.g);
SAFE_PARCEL(output.writeFloat, color.b);
+ SAFE_PARCEL(output.writeFloat, color.a);
SAFE_PARCEL(windowInfoHandle->writeToParcel, &output);
SAFE_PARCEL(output.write, transparentRegion);
- SAFE_PARCEL(output.writeUint32, transform);
+ SAFE_PARCEL(output.writeUint32, bufferTransform);
SAFE_PARCEL(output.writeBool, transformToDisplayInverse);
SAFE_PARCEL(output.writeBool, borderEnabled);
SAFE_PARCEL(output.writeFloat, borderWidth);
@@ -177,7 +176,6 @@
SAFE_PARCEL(input.readFloat, &y);
SAFE_PARCEL(input.readInt32, &z);
SAFE_PARCEL(input.readUint32, &layerStack.id);
- SAFE_PARCEL(input.readFloat, &alpha);
SAFE_PARCEL(input.readUint32, &flags);
@@ -185,7 +183,6 @@
SAFE_PARCEL(matrix.read, input);
SAFE_PARCEL(input.read, crop);
- SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild);
@@ -197,10 +194,13 @@
color.g = tmpFloat;
SAFE_PARCEL(input.readFloat, &tmpFloat);
color.b = tmpFloat;
+ SAFE_PARCEL(input.readFloat, &tmpFloat);
+ color.a = tmpFloat;
+
SAFE_PARCEL(windowInfoHandle->readFromParcel, &input);
SAFE_PARCEL(input.read, transparentRegion);
- SAFE_PARCEL(input.readUint32, &transform);
+ SAFE_PARCEL(input.readUint32, &bufferTransform);
SAFE_PARCEL(input.readBool, &transformToDisplayInverse);
SAFE_PARCEL(input.readBool, &borderEnabled);
SAFE_PARCEL(input.readFloat, &tmpFloat);
@@ -453,7 +453,7 @@
}
if (other.what & eAlphaChanged) {
what |= eAlphaChanged;
- alpha = other.alpha;
+ color.a = other.color.a;
}
if (other.what & eMatrixChanged) {
what |= eMatrixChanged;
@@ -495,12 +495,9 @@
what |= eReparent;
parentSurfaceControlForChild = other.parentSurfaceControlForChild;
}
- if (other.what & eDestroySurface) {
- what |= eDestroySurface;
- }
- if (other.what & eTransformChanged) {
- what |= eTransformChanged;
- transform = other.transform;
+ if (other.what & eBufferTransformChanged) {
+ what |= eBufferTransformChanged;
+ bufferTransform = other.bufferTransform;
}
if (other.what & eTransformToDisplayInverseChanged) {
what |= eTransformToDisplayInverseChanged;
@@ -547,7 +544,7 @@
}
if (other.what & eBackgroundColorChanged) {
what |= eBackgroundColorChanged;
- color = other.color;
+ color.rgb = other.color.rgb;
bgColorAlpha = other.bgColorAlpha;
bgColorDataspace = other.bgColorDataspace;
}
@@ -612,7 +609,7 @@
}
if (other.what & eColorChanged) {
what |= eColorChanged;
- color = other.color;
+ color.rgb = other.color.rgb;
}
if (other.what & eColorSpaceAgnosticChanged) {
what |= eColorSpaceAgnosticChanged;
@@ -634,7 +631,7 @@
}
bool layer_state_t::hasValidBuffer() const {
- return bufferData && (bufferData->buffer || bufferData->cachedBuffer.isValid());
+ return bufferData && (bufferData->hasBuffer() || bufferData->cachedBuffer.isValid());
}
status_t layer_state_t::matrix22_t::write(Parcel& output) const {
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 4b4d46a..c4fb1cf 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -56,6 +56,12 @@
namespace {
+enum {
+ // moved from nativewindow/include/system/window.h, to be removed
+ NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
+ NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+};
+
bool isInterceptorRegistrationOp(int op) {
return op == NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR ||
op == NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR ||
@@ -348,34 +354,25 @@
return NO_ERROR;
}
+// Deprecated(b/242763577): to be removed, this method should not be used
+// The reason this method still exists here is to support compiled vndk
+// Surface support should not be tied to the display
+// Return true since most displays should have this support
status_t Surface::getWideColorSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
- if (display == nullptr) {
- return NAME_NOT_FOUND;
- }
-
- *supported = false;
- binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported);
- return statusTFromBinderStatus(status);
+ *supported = true;
+ return NO_ERROR;
}
+// Deprecated(b/242763577): to be removed, this method should not be used
+// The reason this method still exists here is to support compiled vndk
+// Surface support should not be tied to the display
+// Return true since most displays should have this support
status_t Surface::getHdrSupport(bool* supported) {
ATRACE_CALL();
- const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
- if (display == nullptr) {
- return NAME_NOT_FOUND;
- }
-
- gui::DynamicDisplayInfo info;
- if (binder::Status status = composerServiceAIDL()->getDynamicDisplayInfo(display, &info);
- !status.isOk()) {
- return statusTFromBinderStatus(status);
- }
-
- *supported = !info.hdrCapabilities.supportedHdrTypes.empty();
+ *supported = true;
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 73d8a4a..a5879a7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "SurfaceComposerClient"
+#include <semaphore.h>
#include <stdint.h>
#include <sys/types.h>
@@ -24,6 +25,7 @@
#include <android/gui/ISurfaceComposerClient.h>
#include <android/gui/IWindowInfosListener.h>
#include <android/os/IInputConstants.h>
+#include <gui/TraceUtils.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/SortedVector.h>
@@ -356,7 +358,8 @@
transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
- surfaceStats.eventStats);
+ surfaceStats.eventStats,
+ surfaceStats.currentMaxAcquiredBufferCount);
}
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
@@ -381,7 +384,8 @@
transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
transactionStats.presentFence,
surfaceStats.previousReleaseFence, surfaceStats.transformHint,
- surfaceStats.eventStats);
+ surfaceStats.eventStats,
+ surfaceStats.currentMaxAcquiredBufferCount);
if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl]
@@ -627,7 +631,6 @@
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
: mId(other.mId),
- mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
mAnimation(other.mAnimation),
mEarlyWakeupStart(other.mEarlyWakeupStart),
@@ -662,7 +665,6 @@
status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
const uint64_t transactionId = parcel->readUint64();
- const uint32_t forceSynchronous = parcel->readUint32();
const uint32_t transactionNestCount = parcel->readUint32();
const bool animation = parcel->readBool();
const bool earlyWakeupStart = parcel->readBool();
@@ -739,7 +741,6 @@
// Parsing was successful. Update the object.
mId = transactionId;
- mForceSynchronous = forceSynchronous;
mTransactionNestCount = transactionNestCount;
mAnimation = animation;
mEarlyWakeupStart = earlyWakeupStart;
@@ -770,7 +771,6 @@
const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers();
parcel->writeUint64(mId);
- parcel->writeUint32(mForceSynchronous);
parcel->writeUint32(mTransactionNestCount);
parcel->writeBool(mAnimation);
parcel->writeBool(mEarlyWakeupStart);
@@ -890,7 +890,6 @@
mListenerCallbacks.clear();
mInputWindowCommands.clear();
mMayContainBuffer = false;
- mForceSynchronous = 0;
mTransactionNestCount = 0;
mAnimation = false;
mEarlyWakeupStart = false;
@@ -912,9 +911,14 @@
uncacheBuffer.token = BufferCache::getInstance().getToken();
uncacheBuffer.id = cacheId;
- sf->setTransactionState(FrameTimelineInfo{}, {}, {}, ISurfaceComposer::eOneWay,
- Transaction::getDefaultApplyToken(), {}, systemTime(), true,
- uncacheBuffer, false, {}, generateId());
+ status_t status =
+ sf->setTransactionState(FrameTimelineInfo{}, {}, {}, ISurfaceComposer::eOneWay,
+ Transaction::getDefaultApplyToken(), {}, systemTime(), true,
+ uncacheBuffer, false, {}, generateId());
+ if (status != NO_ERROR) {
+ ALOGE_AND_TRACE("SurfaceComposerClient::doUncacheBufferTransaction - %s",
+ strerror(-status));
+ }
}
void SurfaceComposerClient::Transaction::cacheBuffers() {
@@ -963,12 +967,55 @@
}
}
+class SyncCallback {
+public:
+ static void function(void* callbackContext, nsecs_t /* latchTime */,
+ const sp<Fence>& /* presentFence */,
+ const std::vector<SurfaceControlStats>& /* stats */) {
+ if (!callbackContext) {
+ ALOGE("failed to get callback context for SyncCallback");
+ }
+ SyncCallback* helper = static_cast<SyncCallback*>(callbackContext);
+ LOG_ALWAYS_FATAL_IF(sem_post(&helper->mSemaphore), "sem_post failed");
+ }
+ ~SyncCallback() {
+ if (mInitialized) {
+ LOG_ALWAYS_FATAL_IF(sem_destroy(&mSemaphore), "sem_destroy failed");
+ }
+ }
+ void init() {
+ LOG_ALWAYS_FATAL_IF(clock_gettime(CLOCK_MONOTONIC, &mTimeoutTimespec) == -1,
+ "clock_gettime() fail! in SyncCallback::init");
+ mTimeoutTimespec.tv_sec += 4;
+ LOG_ALWAYS_FATAL_IF(sem_init(&mSemaphore, 0, 0), "sem_init failed");
+ mInitialized = true;
+ }
+ void wait() {
+ int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &mTimeoutTimespec);
+ if (result && errno != ETIMEDOUT && errno != EINTR) {
+ LOG_ALWAYS_FATAL("sem_clockwait failed(%d)", errno);
+ } else if (errno == ETIMEDOUT) {
+ ALOGW("Sync transaction timed out waiting for commit callback.");
+ }
+ }
+ void* getContext() { return static_cast<void*>(this); }
+
+private:
+ sem_t mSemaphore;
+ bool mInitialized = false;
+ timespec mTimeoutTimespec;
+};
+
status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay) {
if (mStatus != NO_ERROR) {
return mStatus;
}
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SyncCallback syncCallback;
+ if (synchronous) {
+ syncCallback.init();
+ addTransactionCommittedCallback(syncCallback.function, syncCallback.getContext());
+ }
bool hasListenerCallbacks = !mListenerCallbacks.empty();
std::vector<ListenerCallbacks> listenerCallbacks;
@@ -1003,27 +1050,22 @@
Vector<DisplayState> displayStates;
uint32_t flags = 0;
- mForceSynchronous |= synchronous;
-
- for (auto const& kv : mComposerStates){
+ for (auto const& kv : mComposerStates) {
composerStates.add(kv.second);
}
displayStates = std::move(mDisplayStates);
- if (mForceSynchronous) {
- flags |= ISurfaceComposer::eSynchronous;
- }
if (mAnimation) {
flags |= ISurfaceComposer::eAnimation;
}
if (oneWay) {
- if (mForceSynchronous) {
- ALOGE("Transaction attempted to set synchronous and one way at the same time"
- " this is an invalid request. Synchronous will win for safety");
- } else {
- flags |= ISurfaceComposer::eOneWay;
- }
+ if (synchronous) {
+ ALOGE("Transaction attempted to set synchronous and one way at the same time"
+ " this is an invalid request. Synchronous will win for safety");
+ } else {
+ flags |= ISurfaceComposer::eOneWay;
+ }
}
// If both mEarlyWakeupStart and mEarlyWakeupEnd are set
@@ -1037,6 +1079,7 @@
sp<IBinder> applyToken = mApplyToken ? mApplyToken : sApplyToken;
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
@@ -1046,6 +1089,10 @@
// Clear the current states and flags
clear();
+ if (synchronous) {
+ syncCallback.wait();
+ }
+
mStatus = NO_ERROR;
return NO_ERROR;
}
@@ -1089,11 +1136,6 @@
return physicalDisplayIds;
}
-std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
- ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
- return instance.getInternalDisplayId();
-}
-
sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
sp<IBinder> display = nullptr;
binder::Status status =
@@ -1102,11 +1144,6 @@
return status.isOk() ? display : nullptr;
}
-sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
- ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
- return instance.getInternalDisplayToken();
-}
-
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
mAnimation = true;
}
@@ -1262,7 +1299,7 @@
ALOGE("SurfaceComposerClient::Transaction::setAlpha: invalid alpha %f, clamping", alpha);
}
s->what |= layer_state_t::eAlphaChanged;
- s->alpha = std::clamp(alpha, 0.f, 1.f);
+ s->color.a = std::clamp(alpha, 0.f, 1.f);
registerSurfaceControlForCallback(sc);
return *this;
@@ -1393,7 +1430,7 @@
return *this;
}
s->what |= layer_state_t::eColorChanged;
- s->color = color;
+ s->color.rgb = color;
registerSurfaceControlForCallback(sc);
return *this;
@@ -1408,7 +1445,7 @@
}
s->what |= layer_state_t::eBackgroundColorChanged;
- s->color = color;
+ s->color.rgb = color;
s->bgColorAlpha = alpha;
s->bgColorDataspace = dataspace;
@@ -1423,8 +1460,8 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eTransformChanged;
- s->transform = transform;
+ s->what |= layer_state_t::eBufferTransformChanged;
+ s->bufferTransform = transform;
registerSurfaceControlForCallback(sc);
return *this;
@@ -2021,7 +2058,6 @@
s.layerStackSpaceRect = layerStackRect;
s.orientedDisplaySpaceRect = displayRect;
s.what |= DisplayState::eDisplayProjectionChanged;
- mForceSynchronous = true; // TODO: do we actually still need this?
}
void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
@@ -2116,6 +2152,10 @@
return s;
}
+static std::string toString(const String16& string) {
+ return std::string(String8(string).c_str());
+}
+
status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
PixelFormat format,
sp<SurfaceControl>* outSurface, int32_t flags,
@@ -2135,7 +2175,8 @@
}
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
- *outSurface = new SurfaceControl(this, result.handle, result.layerId, w, h, format,
+ *outSurface = new SurfaceControl(this, result.handle, result.layerId,
+ toString(result.layerName), w, h, format,
result.transformHint, flags);
}
}
@@ -2148,21 +2189,21 @@
}
sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle();
- gui::MirrorSurfaceResult result;
+ gui::CreateSurfaceResult result;
const binder::Status status = mClient->mirrorSurface(mirrorFromHandle, &result);
const status_t err = statusTFromBinderStatus(status);
if (err == NO_ERROR) {
- return new SurfaceControl(this, result.handle, result.layerId);
+ return new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName));
}
return nullptr;
}
sp<SurfaceControl> SurfaceComposerClient::mirrorDisplay(DisplayId displayId) {
- gui::MirrorSurfaceResult result;
+ gui::CreateSurfaceResult result;
const binder::Status status = mClient->mirrorDisplay(displayId.value, &result);
const status_t err = statusTFromBinderStatus(status);
if (err == NO_ERROR) {
- return new SurfaceControl(this, result.handle, result.layerId);
+ return new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName));
}
return nullptr;
}
@@ -2202,18 +2243,6 @@
// ----------------------------------------------------------------------------
-status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
- sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
- binder::Status status = sf->enableVSyncInjections(enable);
- return statusTFromBinderStatus(status);
-}
-
-status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
- sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
- binder::Status status = sf->injectVSync(when);
- return statusTFromBinderStatus(status);
-}
-
status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
ui::DisplayState* state) {
gui::DisplayState ds;
@@ -2716,8 +2745,7 @@
ComposerServiceAIDL::getComposerService()->getDisplayDecorationSupport(displayToken,
&gsupport);
std::optional<DisplayDecorationSupport> support;
- // TODO (b/241277093): Remove `false && ` once b/241278870 is fixed.
- if (false && status.isOk() && gsupport.has_value()) {
+ if (status.isOk() && gsupport.has_value()) {
support.emplace(DisplayDecorationSupport{
.format =
static_cast<aidl::android::hardware::graphics::common::PixelFormat>(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 84257de..7aee882 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -49,11 +49,12 @@
// ============================================================================
SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
- int32_t layerId, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t transform, uint32_t flags)
+ int32_t layerId, const std::string& name, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t transform, uint32_t flags)
: mClient(client),
mHandle(handle),
mLayerId(layerId),
+ mName(name),
mTransformHint(transform),
mWidth(w),
mHeight(h),
@@ -65,6 +66,7 @@
mHandle = other->mHandle;
mTransformHint = other->mTransformHint;
mLayerId = other->mLayerId;
+ mName = other->mName;
mWidth = other->mWidth;
mHeight = other->mHeight;
mFormat = other->mFormat;
@@ -185,6 +187,10 @@
return mLayerId;
}
+const std::string& SurfaceControl::getName() const {
+ return mName;
+}
+
sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer()
{
getSurface();
@@ -212,6 +218,7 @@
SAFE_PARCEL(parcel.writeStrongBinder, ISurfaceComposerClient::asBinder(mClient->getClient()));
SAFE_PARCEL(parcel.writeStrongBinder, mHandle);
SAFE_PARCEL(parcel.writeInt32, mLayerId);
+ SAFE_PARCEL(parcel.writeUtf8AsUtf16, mName);
SAFE_PARCEL(parcel.writeUint32, mTransformHint);
SAFE_PARCEL(parcel.writeUint32, mWidth);
SAFE_PARCEL(parcel.writeUint32, mHeight);
@@ -225,6 +232,7 @@
sp<IBinder> client;
sp<IBinder> handle;
int32_t layerId;
+ std::string layerName;
uint32_t transformHint;
uint32_t width;
uint32_t height;
@@ -233,16 +241,17 @@
SAFE_PARCEL(parcel.readStrongBinder, &client);
SAFE_PARCEL(parcel.readStrongBinder, &handle);
SAFE_PARCEL(parcel.readInt32, &layerId);
+ SAFE_PARCEL(parcel.readUtf8FromUtf16, &layerName);
SAFE_PARCEL(parcel.readUint32, &transformHint);
SAFE_PARCEL(parcel.readUint32, &width);
SAFE_PARCEL(parcel.readUint32, &height);
SAFE_PARCEL(parcel.readUint32, &format);
// We aren't the original owner of the surface.
- *outSurfaceControl =
- new SurfaceControl(new SurfaceComposerClient(
- interface_cast<ISurfaceComposerClient>(client)),
- handle.get(), layerId, width, height, format, transformHint);
+ *outSurfaceControl = new SurfaceControl(new SurfaceComposerClient(
+ interface_cast<ISurfaceComposerClient>(client)),
+ handle.get(), layerId, layerName, width, height, format,
+ transformHint);
return NO_ERROR;
}
diff --git a/libs/gui/TransactionTracing.cpp b/libs/gui/TransactionTracing.cpp
deleted file mode 100644
index 59450fb..0000000
--- a/libs/gui/TransactionTracing.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "gui/TransactionTracing.h"
-#include "android/gui/ISurfaceComposer.h"
-
-#include <private/gui/ComposerServiceAIDL.h>
-
-namespace android {
-
-sp<TransactionTraceListener> TransactionTraceListener::sInstance = nullptr;
-std::mutex TransactionTraceListener::sMutex;
-
-TransactionTraceListener::TransactionTraceListener() {}
-
-sp<TransactionTraceListener> TransactionTraceListener::getInstance() {
- const std::lock_guard<std::mutex> lock(sMutex);
-
- if (sInstance == nullptr) {
- sInstance = new TransactionTraceListener;
-
- sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
- sf->addTransactionTraceListener(sInstance);
- }
-
- return sInstance;
-}
-
-binder::Status TransactionTraceListener::onToggled(bool enabled) {
- ALOGD("TransactionTraceListener: onToggled listener called");
- mTracingEnabled = enabled;
-
- return binder::Status::ok();
-}
-
-bool TransactionTraceListener::isTracingEnabled() {
- return mTracingEnabled;
-}
-
-} // namespace android
diff --git a/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl b/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl
index 39e4916..eea12dc 100644
--- a/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl
+++ b/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl
@@ -20,5 +20,6 @@
parcelable CreateSurfaceResult {
IBinder handle;
int layerId;
+ String layerName;
int transformHint;
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 53d0a04..92d9e77 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -36,7 +36,6 @@
import android.gui.IRegionSamplingListener;
import android.gui.IScreenCaptureListener;
import android.gui.ISurfaceComposerClient;
-import android.gui.ITransactionTraceListener;
import android.gui.ITunnelModeEnabledListener;
import android.gui.IWindowInfosListener;
import android.gui.LayerCaptureArgs;
@@ -226,10 +225,6 @@
*/
PullAtomData onPullAtom(int atomId);
- oneway void enableVSyncInjections(boolean enable);
-
- oneway void injectVSync(long when);
-
/**
* Gets the list of active layers in Z order for debugging purposes
*
@@ -454,11 +449,6 @@
void setOverrideFrameRate(int uid, float frameRate);
/**
- * Adds a TransactionTraceListener to listen for transaction tracing state updates.
- */
- void addTransactionTraceListener(ITransactionTraceListener listener);
-
- /**
* Gets priority of the RenderEngine in SurfaceFlinger.
*/
int getGpuContextPriority();
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
index b8ee4d7..68781ce 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
@@ -19,7 +19,6 @@
import android.gui.CreateSurfaceResult;
import android.gui.FrameStats;
import android.gui.LayerMetadata;
-import android.gui.MirrorSurfaceResult;
/** @hide */
interface ISurfaceComposerClient {
@@ -58,7 +57,7 @@
*/
FrameStats getLayerFrameStats(IBinder handle);
- MirrorSurfaceResult mirrorSurface(IBinder mirrorFromHandle);
+ CreateSurfaceResult mirrorSurface(IBinder mirrorFromHandle);
- MirrorSurfaceResult mirrorDisplay(long displayId);
+ CreateSurfaceResult mirrorDisplay(long displayId);
}
diff --git a/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl b/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl
deleted file mode 100644
index 5cd12fd..0000000
--- a/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl
+++ /dev/null
@@ -1,6 +0,0 @@
-package android.gui;
-
-/** @hide */
-interface ITransactionTraceListener {
- void onToggled(boolean enabled);
-}
\ No newline at end of file
diff --git a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
index c97770b..761f08f 100644
--- a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
+++ b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android-base/stringprintf.h>
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
@@ -91,8 +92,10 @@
const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
sp<BnGraphicBufferProducer> producer;
- return sp<SurfaceControl>::make(client, handle, mFdp.ConsumeIntegral<int32_t>(),
- mFdp.ConsumeIntegral<uint32_t>(),
+ uint32_t layerId = mFdp.ConsumeIntegral<uint32_t>();
+ std::string layerName = base::StringPrintf("#%d", layerId);
+ return sp<SurfaceControl>::make(client, handle, layerId, layerName,
+ mFdp.ConsumeIntegral<int32_t>(),
mFdp.ConsumeIntegral<uint32_t>(),
mFdp.ConsumeIntegral<int32_t>(),
mFdp.ConsumeIntegral<uint32_t>(),
@@ -145,7 +148,8 @@
sp<Fence> presentFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
SurfaceControlStats controlStats(surface, mFdp.ConsumeIntegral<int64_t>(),
mFdp.ConsumeIntegral<int64_t>(), presentFence, previousFence,
- mFdp.ConsumeIntegral<uint32_t>(), frameStats);
+ mFdp.ConsumeIntegral<uint32_t>(), frameStats,
+ mFdp.ConsumeIntegral<uint32_t>());
stats.push_back(controlStats);
}
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index 1dda97e..2025170 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -102,8 +102,6 @@
MOCK_METHOD(binder::Status, overrideHdrTypes, (const sp<IBinder>&, const std::vector<int32_t>&),
(override));
MOCK_METHOD(binder::Status, onPullAtom, (int32_t, gui::PullAtomData*), (override));
- MOCK_METHOD(binder::Status, enableVSyncInjections, (bool), (override));
- MOCK_METHOD(binder::Status, injectVSync, (int64_t), (override));
MOCK_METHOD(binder::Status, getLayerDebugInfo, (std::vector<gui::LayerDebugInfo>*), (override));
MOCK_METHOD(binder::Status, getColorManagement, (bool*), (override));
MOCK_METHOD(binder::Status, getCompositionPreference, (gui::CompositionPreference*),
@@ -148,8 +146,6 @@
MOCK_METHOD(binder::Status, getDisplayDecorationSupport,
(const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override));
MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override));
- MOCK_METHOD(binder::Status, addTransactionTraceListener,
- (const sp<gui::ITransactionTraceListener>&), (override));
MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override));
MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override));
MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
@@ -172,11 +168,11 @@
(const sp<IBinder>& handle, gui::FrameStats* outStats), (override));
MOCK_METHOD(binder::Status, mirrorSurface,
- (const sp<IBinder>& mirrorFromHandle, gui::MirrorSurfaceResult* outResult),
+ (const sp<IBinder>& mirrorFromHandle, gui::CreateSurfaceResult* outResult),
(override));
MOCK_METHOD(binder::Status, mirrorDisplay,
- (int64_t displayId, gui::MirrorSurfaceResult* outResult), (override));
+ (int64_t displayId, gui::CreateSurfaceResult* outResult), (override));
};
class FakeDisplayEventDispatcher : public DisplayEventDispatcher {
diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
index 48c90c5..eecbe0f 100644
--- a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
+++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
@@ -18,6 +18,7 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <libgui_fuzzer_utils.h>
+#include "android-base/stringprintf.h"
using namespace android;
@@ -175,7 +176,9 @@
uint32_t flags = mFdp.ConsumeIntegral<uint32_t>();
int32_t format = mFdp.ConsumeIntegral<int32_t>();
int32_t layerId = mFdp.ConsumeIntegral<int32_t>();
- return new SurfaceControl(client, handle, layerId, width, height, format, transformHint, flags);
+ std::string layerName = base::StringPrintf("#%d", layerId);
+ return new SurfaceControl(client, handle, layerId, layerName, width, height, format,
+ transformHint, flags);
}
void SurfaceComposerClientFuzzer::invokeSurfaceComposerTransaction() {
@@ -268,10 +271,6 @@
sp<Surface> surfaceParent(
new Surface(producer, mFdp.ConsumeBool() /*controlledByApp*/, handle));
- SurfaceComposerClient::enableVSyncInjections(mFdp.ConsumeBool() /*secure*/);
- nsecs_t when = mFdp.ConsumeIntegral<uint32_t>();
- SurfaceComposerClient::injectVSync(when);
-
fuzzOnPullAtom();
SurfaceComposerClient::setDisplayContentSamplingEnabled(displayToken,
mFdp.ConsumeBool() /*enable*/,
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 4535c98..827a6cc 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -92,9 +92,12 @@
const std::vector<SurfaceControlStats>& stats);
void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount);
+ void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount);
void syncNextTransaction(std::function<void(SurfaceComposerClient::Transaction*)> callback,
bool acquireSingleBuffer = true);
void stopContinuousSyncTransaction();
+
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void applyPendingTransactions(uint64_t frameNumber);
SurfaceComposerClient::Transaction* gatherPendingTransactions(uint64_t frameNumber);
@@ -173,6 +176,12 @@
struct ReleasedBuffer {
ReleaseCallbackId callbackId;
sp<Fence> releaseFence;
+ bool operator==(const ReleasedBuffer& rhs) const {
+ // Only compare Id so if we somehow got two callbacks
+ // with different fences we don't decrement mNumAcquired
+ // too far.
+ return rhs.callbackId == callbackId;
+ }
};
std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 1e85131..e91d754 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -23,7 +23,6 @@
#include <android/gui/IHdrLayerInfoListener.h>
#include <android/gui/IRegionSamplingListener.h>
#include <android/gui/IScreenCaptureListener.h>
-#include <android/gui/ITransactionTraceListener.h>
#include <android/gui/ITunnelModeEnabledListener.h>
#include <android/gui/IWindowInfosListener.h>
#include <binder/IBinder.h>
@@ -95,7 +94,6 @@
// flags for setTransactionState()
enum {
- eSynchronous = 0x01,
eAnimation = 0x02,
// Explicit indication that this transaction and others to follow will likely result in a
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c8927ad..45272e7 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -148,12 +148,14 @@
enum {
ePositionChanged = 0x00000001,
eLayerChanged = 0x00000002,
- // unused = 0x00000004,
+ /* unused = 0x00000004, */
eAlphaChanged = 0x00000008,
eMatrixChanged = 0x00000010,
eTransparentRegionChanged = 0x00000020,
eFlagsChanged = 0x00000040,
eLayerStackChanged = 0x00000080,
+ /* unused = 0x00000100, */
+ /* unused = 0x00000200, */
eDimmingEnabledChanged = 0x00000400,
eShadowRadiusChanged = 0x00000800,
eRenderBorderChanged = 0x00001000,
@@ -161,8 +163,8 @@
eRelativeLayerChanged = 0x00004000,
eReparent = 0x00008000,
eColorChanged = 0x00010000,
- eDestroySurface = 0x00020000,
- eTransformChanged = 0x00040000,
+ /* unused = 0x00020000, */
+ eBufferTransformChanged = 0x00040000,
eTransformToDisplayInverseChanged = 0x00080000,
eCropChanged = 0x00100000,
eBufferChanged = 0x00200000,
@@ -218,25 +220,22 @@
float y;
int32_t z;
ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK;
- float alpha;
uint32_t flags;
uint32_t mask;
uint8_t reserved;
matrix22_t matrix;
float cornerRadius;
uint32_t backgroundBlurRadius;
- sp<SurfaceControl> reparentSurfaceControl;
sp<SurfaceControl> relativeLayerSurfaceControl;
sp<SurfaceControl> parentSurfaceControlForChild;
- half3 color;
+ half4 color;
// non POD must be last. see write/read
Region transparentRegion;
-
- uint32_t transform;
+ uint32_t bufferTransform;
bool transformToDisplayInverse;
Rect crop;
std::shared_ptr<BufferData> bufferData = nullptr;
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 634acb6..1f19f4e 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -187,8 +187,8 @@
nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
nsecs_t* outReleaseTime);
- status_t getWideColorSupport(bool* supported);
- status_t getHdrSupport(bool* supported);
+ status_t getWideColorSupport(bool* supported) __attribute__((__deprecated__));
+ status_t getHdrSupport(bool* supported) __attribute__((__deprecated__));
status_t getUniqueId(uint64_t* outId) const;
status_t getConsumerUsage(uint64_t* outUsage) const;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 25042cf..36969db 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -69,14 +69,16 @@
SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence,
const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
- uint32_t hint, FrameEventHistoryStats eventStats)
+ uint32_t hint, FrameEventHistoryStats eventStats,
+ uint32_t currentMaxAcquiredBufferCount)
: surfaceControl(sc),
latchTime(latchTime),
acquireTimeOrFence(std::move(acquireTimeOrFence)),
presentFence(presentFence),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
- frameEventStats(eventStats) {}
+ frameEventStats(eventStats),
+ currentMaxAcquiredBufferCount(currentMaxAcquiredBufferCount) {}
sp<SurfaceControl> surfaceControl;
nsecs_t latchTime = -1;
@@ -85,6 +87,7 @@
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
FrameEventHistoryStats frameEventStats;
+ uint32_t currentMaxAcquiredBufferCount = 0;
};
using TransactionCompletedCallbackTakesContext =
@@ -355,15 +358,9 @@
//! Get stable IDs for connected physical displays
static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
- static std::optional<PhysicalDisplayId> getInternalDisplayId();
//! Get token for a physical display given its stable ID
static sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId);
- static sp<IBinder> getInternalDisplayToken();
-
- static status_t enableVSyncInjections(bool enable);
-
- static status_t injectVSync(nsecs_t when);
struct SCHash {
std::size_t operator()(const sp<SurfaceControl>& sc) const {
@@ -407,7 +404,6 @@
uint64_t mId;
- uint32_t mForceSynchronous = 0;
uint32_t mTransactionNestCount = 0;
bool mAnimation = false;
bool mEarlyWakeupStart = false;
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index e4a1350..1d4fc7f 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -78,6 +78,7 @@
sp<IBinder> getHandle() const;
sp<IBinder> getLayerStateHandle() const;
int32_t getLayerId() const;
+ const std::string& getName() const;
sp<IGraphicBufferProducer> getIGraphicBufferProducer();
@@ -94,8 +95,9 @@
explicit SurfaceControl(const sp<SurfaceControl>& other);
SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
- int32_t layerId, uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0,
- uint32_t transformHint = 0, uint32_t flags = 0);
+ int32_t layerId, const std::string& layerName, uint32_t width = 0,
+ uint32_t height = 0, PixelFormat format = 0, uint32_t transformHint = 0,
+ uint32_t flags = 0);
sp<SurfaceControl> getParentingLayer();
@@ -121,6 +123,7 @@
mutable sp<BLASTBufferQueue> mBbq;
mutable sp<SurfaceControl> mBbqChild;
int32_t mLayerId = 0;
+ std::string mName;
uint32_t mTransformHint = 0;
uint32_t mWidth = 0;
uint32_t mHeight = 0;
diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h
index 4c01683..441b833 100644
--- a/libs/gui/include/gui/TraceUtils.h
+++ b/libs/gui/include/gui/TraceUtils.h
@@ -30,6 +30,12 @@
#define ATRACE_FORMAT_INSTANT(fmt, ...) \
(CC_UNLIKELY(ATRACE_ENABLED()) && (TraceUtils::instantFormat(fmt, ##__VA_ARGS__), true))
+#define ALOGE_AND_TRACE(fmt, ...) \
+ do { \
+ ALOGE(fmt, ##__VA_ARGS__); \
+ ATRACE_FORMAT_INSTANT(fmt, ##__VA_ARGS__); \
+ } while (false)
+
namespace android {
class TraceUtils {
diff --git a/libs/gui/include/gui/TransactionTracing.h b/libs/gui/include/gui/TransactionTracing.h
deleted file mode 100644
index 9efba47..0000000
--- a/libs/gui/include/gui/TransactionTracing.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/gui/BnTransactionTraceListener.h>
-#include <utils/Mutex.h>
-
-namespace android {
-
-class TransactionTraceListener : public gui::BnTransactionTraceListener {
- static std::mutex sMutex;
- static sp<TransactionTraceListener> sInstance;
-
- TransactionTraceListener();
-
-public:
- static sp<TransactionTraceListener> getInstance();
-
- binder::Status onToggled(bool enabled) override;
-
- bool isTracingEnabled();
-
-private:
- bool mTracingEnabled = false;
-};
-
-} // namespace android
diff --git a/libs/gui/include/gui/fake/BufferData.h b/libs/gui/include/gui/fake/BufferData.h
new file mode 100644
index 0000000..725d11c
--- /dev/null
+++ b/libs/gui/include/gui/fake/BufferData.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gui/LayerState.h>
+
+namespace android::fake {
+
+// Class which exposes buffer properties from BufferData without holding on to an actual buffer
+class BufferData : public android::BufferData {
+public:
+ BufferData(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat,
+ uint64_t outUsage)
+ : mBufferId(bufferId),
+ mWidth(width),
+ mHeight(height),
+ mPixelFormat(pixelFormat),
+ mOutUsage(outUsage) {}
+ bool hasBuffer() const override { return mBufferId != 0; }
+ bool hasSameBuffer(const android::BufferData& other) const override {
+ return getId() == other.getId() && frameNumber == other.frameNumber;
+ }
+ uint32_t getWidth() const override { return mWidth; }
+ uint32_t getHeight() const override { return mHeight; }
+ uint64_t getId() const override { return mBufferId; }
+ PixelFormat getPixelFormat() const override { return mPixelFormat; }
+ uint64_t getUsage() const override { return mOutUsage; }
+
+private:
+ uint64_t mBufferId;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ int32_t mPixelFormat;
+ uint64_t mOutUsage;
+};
+
+} // namespace android::fake
diff --git a/libs/gui/include/gui/test/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
index 62d1496..08785b4 100644
--- a/libs/gui/include/gui/test/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -135,7 +135,8 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
const auto& [surfaceControl, latch, acquireTimeOrFence, presentFence,
- previousReleaseFence, transformHint, frameEvents] = surfaceControlStats;
+ previousReleaseFence, transformHint, frameEvents, ignore] =
+ surfaceControlStats;
ASSERT_TRUE(std::holds_alternative<nsecs_t>(acquireTimeOrFence));
ASSERT_EQ(std::get<nsecs_t>(acquireTimeOrFence) > 0,
diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h
index 2963583..6352a58 100644
--- a/libs/gui/include/private/gui/ComposerServiceAIDL.h
+++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h
@@ -51,28 +51,6 @@
// Get a connection to the Composer Service. This will block until
// a connection is established. Returns null if permission is denied.
static sp<gui::ISurfaceComposer> getComposerService();
-
- // the following two methods are moved from ISurfaceComposer.h
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- std::optional<PhysicalDisplayId> getInternalDisplayId() const {
- std::vector<int64_t> displayIds;
- binder::Status status = mComposerService->getPhysicalDisplayIds(&displayIds);
- return (!status.isOk() || displayIds.empty())
- ? std::nullopt
- : DisplayId::fromValue<PhysicalDisplayId>(
- static_cast<uint64_t>(displayIds.front()));
- }
-
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- sp<IBinder> getInternalDisplayToken() const {
- const auto displayId = getInternalDisplayId();
- if (!displayId) return nullptr;
- sp<IBinder> display;
- binder::Status status =
- mComposerService->getPhysicalDisplayToken(static_cast<int64_t>(displayId->value),
- &display);
- return status.isOk() ? display : nullptr;
- }
};
// ---------------------------------------------------------------------------
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index c4c2fa5..cf2593d 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -188,7 +188,10 @@
void SetUp() {
mComposer = ComposerService::getComposerService();
mClient = new SurfaceComposerClient();
- mDisplayToken = mClient->getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ // display 0 is picked as this test is not much display depedent
+ mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_NE(nullptr, mDisplayToken.get());
Transaction t;
t.setDisplayLayerStack(mDisplayToken, ui::DEFAULT_LAYER_STACK);
diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp
index b647aab..0a2750a 100644
--- a/libs/gui/tests/DisplayedContentSampling_test.cpp
+++ b/libs/gui/tests/DisplayedContentSampling_test.cpp
@@ -32,7 +32,10 @@
void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(OK, mComposerClient->initCheck());
- mDisplayToken = mComposerClient->getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ // display 0 is picked for now, can extend to support all displays if needed
+ mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_TRUE(mDisplayToken);
}
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 2637f59..3344e0b 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -360,8 +360,10 @@
void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
- const auto display = mComposerClient->getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ // display 0 is picked for now, can extend to support all displays if needed
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_NE(display, nullptr);
ui::DisplayMode mode;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 0c99cd2..346b686 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -263,7 +263,10 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ // display 0 is picked for now, can extend to support all displays if needed
+ const sp<IBinder> display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_FALSE(display == nullptr);
DisplayCaptureArgs captureArgs;
@@ -848,10 +851,6 @@
return binder::Status::ok();
}
- binder::Status enableVSyncInjections(bool /*enable*/) override { return binder::Status::ok(); }
-
- binder::Status injectVSync(int64_t /*when*/) override { return binder::Status::ok(); }
-
binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* /*outLayers*/) override {
return binder::Status::ok();
}
@@ -974,11 +973,6 @@
return binder::Status::ok();
}
- binder::Status addTransactionTraceListener(
- const sp<gui::ITransactionTraceListener>& /*listener*/) override {
- return binder::Status::ok();
- }
-
binder::Status getGpuContextPriority(int32_t* /*outPriority*/) override {
return binder::Status::ok();
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 29e02cf..34ef7b4 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -89,7 +89,6 @@
shared_libs: [
"libutils",
"libbinder",
- "libui",
],
static_libs: [
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 3fe03c7..4751a7d 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -182,6 +182,7 @@
mSources(other.mSources),
mKeyboardType(other.mKeyboardType),
mKeyCharacterMap(other.mKeyCharacterMap),
+ mSupportsUsi(other.mSupportsUsi),
mHasVibrator(other.mHasVibrator),
mHasBattery(other.mHasBattery),
mHasButtonUnderPad(other.mHasButtonUnderPad),
@@ -210,6 +211,7 @@
mHasBattery = false;
mHasButtonUnderPad = false;
mHasSensor = false;
+ mSupportsUsi = false;
mMotionRanges.clear();
mSensors.clear();
mLights.clear();
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index c53811a..5aae37d 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -10,6 +10,7 @@
cc_test {
name: "libinput_tests",
+ host_supported: true,
srcs: [
"IdGenerator_test.cpp",
"InputChannel_test.cpp",
@@ -24,6 +25,7 @@
static_libs: [
"libgui_window_info_static",
"libinput",
+ "libui-types",
],
cflags: [
"-Wall",
@@ -35,11 +37,13 @@
"libbinder",
"libcutils",
"liblog",
- "libui",
"libutils",
"libvintf",
],
data: ["data/*"],
+ test_options: {
+ unit_test: true,
+ },
test_suites: ["device-tests"],
}
@@ -60,7 +64,6 @@
"libcutils",
"libutils",
"libbinder",
- "libui",
"libbase",
],
}
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index e872fa4..2344463 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -65,6 +65,9 @@
}
void SetUp() override {
+#if !defined(__ANDROID__)
+ GTEST_SKIP() << "b/253299089 Generic files are currently read directly from device.";
+#endif
loadKeyLayout("Generic");
loadKeyCharacterMap("Generic");
}
@@ -131,6 +134,9 @@
}
TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) {
+#if !defined(__ANDROID__)
+ GTEST_SKIP() << "Can't check kernel configs on host";
+#endif
std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_fake_config.kl";
base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath;
@@ -139,6 +145,9 @@
}
TEST(InputDeviceKeyLayoutTest, LoadsWhenRequiredKernelConfigIsPresent) {
+#if !defined(__ANDROID__)
+ GTEST_SKIP() << "Can't check kernel configs on host";
+#endif
std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_real_config.kl";
base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
ASSERT_TRUE(ret.ok()) << "Cannot load KeyLayout at " << klPath;
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 8b00b5c..bd12663 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -65,8 +65,15 @@
EXPECT_NEAR(actual, target, tolerance);
}
-static void checkVelocity(float Vactual, float Vtarget) {
- EXPECT_NEAR_BY_FRACTION(Vactual, Vtarget, VELOCITY_TOLERANCE);
+static void checkVelocity(std::optional<float> Vactual, std::optional<float> Vtarget) {
+ if (Vactual != std::nullopt) {
+ if (Vtarget == std::nullopt) {
+ FAIL() << "Expected no velocity, but found " << *Vactual;
+ }
+ EXPECT_NEAR_BY_FRACTION(*Vactual, *Vtarget, VELOCITY_TOLERANCE);
+ } else if (Vtarget != std::nullopt) {
+ FAIL() << "Expected velocity, but found no velocity";
+ }
}
static void checkCoefficient(float actual, float target) {
@@ -223,10 +230,10 @@
return events;
}
-static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
- const std::vector<PlanarMotionEventEntry>& motions,
- int32_t axis, float targetVelocity,
- uint32_t pointerId = DEFAULT_POINTER_ID) {
+static std::optional<float> computePlanarVelocity(
+ const VelocityTracker::Strategy strategy,
+ const std::vector<PlanarMotionEventEntry>& motions, int32_t axis,
+ uint32_t pointerId = DEFAULT_POINTER_ID) {
VelocityTracker vt(strategy);
std::vector<MotionEvent> events = createTouchMotionEventStream(motions);
@@ -234,30 +241,44 @@
vt.addMovement(&event);
}
- checkVelocity(vt.getVelocity(axis, pointerId).value_or(0), targetVelocity);
+ return vt.getVelocity(axis, pointerId);
+}
+
+static std::vector<MotionEvent> createMotionEventStream(
+ int32_t axis, const std::vector<std::pair<std::chrono::nanoseconds, float>>& motion) {
+ switch (axis) {
+ case AMOTION_EVENT_AXIS_SCROLL:
+ return createAxisScrollMotionEventStream(motion);
+ default:
+ ADD_FAILURE() << "Axis " << axis << " is not supported";
+ return {};
+ }
+}
+
+static std::optional<float> computeVelocity(
+ const VelocityTracker::Strategy strategy,
+ const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions, int32_t axis) {
+ VelocityTracker vt(strategy);
+
+ for (const MotionEvent& event : createMotionEventStream(axis, motions)) {
+ vt.addMovement(&event);
+ }
+
+ return vt.getVelocity(axis, DEFAULT_POINTER_ID);
+}
+
+static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
+ const std::vector<PlanarMotionEventEntry>& motions,
+ int32_t axis, std::optional<float> targetVelocity,
+ uint32_t pointerId = DEFAULT_POINTER_ID) {
+ checkVelocity(computePlanarVelocity(strategy, motions, axis, pointerId), targetVelocity);
}
static void computeAndCheckAxisScrollVelocity(
const VelocityTracker::Strategy strategy,
const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions,
std::optional<float> targetVelocity) {
- VelocityTracker vt(strategy);
-
- std::vector<MotionEvent> events = createAxisScrollMotionEventStream(motions);
- for (const MotionEvent& event : events) {
- vt.addMovement(&event);
- }
-
- std::optional<float> velocity = vt.getVelocity(AMOTION_EVENT_AXIS_SCROLL, DEFAULT_POINTER_ID);
- if (velocity && !targetVelocity) {
- FAIL() << "Expected no velocity, but found " << *velocity;
- }
- if (!velocity && targetVelocity) {
- FAIL() << "Expected velocity, but found no velocity";
- }
- if (velocity) {
- checkVelocity(*velocity, *targetVelocity);
- }
+ checkVelocity(computeVelocity(strategy, motions, AMOTION_EVENT_AXIS_SCROLL), targetVelocity);
}
static void computeAndCheckQuadraticEstimate(const std::vector<PlanarMotionEventEntry>& motions,
@@ -280,6 +301,20 @@
/*
* ================== VelocityTracker tests generated manually =====================================
*/
+TEST_F(VelocityTrackerTest, TestDefaultStrategiesForPlanarAxes) {
+ std::vector<PlanarMotionEventEntry> motions = {{10ms, {{2, 4}}},
+ {20ms, {{4, 12}}},
+ {30ms, {{6, 20}}},
+ {40ms, {{10, 30}}}};
+
+ EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X),
+ computePlanarVelocity(VelocityTracker::Strategy::DEFAULT, motions,
+ AMOTION_EVENT_AXIS_X));
+ EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y),
+ computePlanarVelocity(VelocityTracker::Strategy::DEFAULT, motions,
+ AMOTION_EVENT_AXIS_Y));
+}
+
TEST_F(VelocityTrackerTest, TestComputedVelocity) {
VelocityTracker::ComputedVelocity computedVelocity;
@@ -975,7 +1010,7 @@
/**
* ================== Multiple pointers ============================================================
*
- * Three fingers quickly tap the screen. Since this is a tap, the velocities should be zero.
+ * Three fingers quickly tap the screen. Since this is a tap, the velocities should be empty.
* If the events with POINTER_UP or POINTER_DOWN are not handled correctly (these should not be
* part of the fitted data), this can cause large velocity values to be reported instead.
*/
@@ -989,12 +1024,14 @@
{ 272700us, {{1063, 1128}, {NAN, NAN}, {NAN, NAN}} },
};
- // Velocity should actually be zero, but we expect 0.016 here instead.
- // This is close enough to zero, and is likely caused by division by a very small number.
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y, 0);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ std::nullopt);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ std::nullopt);
}
/**
@@ -1017,7 +1054,7 @@
/**
* The last movement of a single pointer is ACTION_UP. If there's a long delay between the last
- * ACTION_MOVE and the final ACTION_UP, velocity should be reported as zero because the pointer
+ * ACTION_MOVE and the final ACTION_UP, velocity should be reported as empty because the pointer
* should be assumed to have stopped.
*/
TEST_F(VelocityTrackerTest, LongDelayBeforeActionUp) {
@@ -1027,14 +1064,16 @@
{20ms, {{30, 0}}},
{3000ms, {{30, 0}}}, // ACTION_UP
};
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt);
}
/**
* The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a long delay
* before ACTION_POINTER_UP event, the movement should be assumed to have stopped.
- * The final velocity should be reported as zero for all pointers.
+ * The final velocity should be reported as empty for all pointers.
*/
TEST_F(VelocityTrackerTest, LongDelayBeforeActionPointerUp) {
std::vector<PlanarMotionEventEntry> motions = {
@@ -1045,13 +1084,17 @@
{40ms, {{30, 0}, {400, 0}}},
{3000ms, {{30, 0}}}, // ACTION_POINTER_UP
};
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0,
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt,
/*pointerId*/ 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0,
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt,
/*pointerId*/ 0);
- computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0,
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt,
/*pointerId*/ 1);
- computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0,
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ std::nullopt,
/*pointerId*/ 1);
}
@@ -1227,6 +1270,20 @@
}
// ------------------------------- Hand generated test cases ---------------------------------------
+TEST_F(VelocityTrackerTest, TestDefaultStrategyForAxisScroll) {
+ std::vector<std::pair<std::chrono::nanoseconds, float>> motions = {
+ {10ms, 20},
+ {20ms, 25},
+ {30ms, 50},
+ {40ms, 100},
+ };
+
+ EXPECT_EQ(computeVelocity(VelocityTracker::Strategy::IMPULSE, motions,
+ AMOTION_EVENT_AXIS_SCROLL),
+ computeVelocity(VelocityTracker::Strategy::DEFAULT, motions,
+ AMOTION_EVENT_AXIS_SCROLL));
+}
+
TEST_F(VelocityTrackerTest, AxisScrollVelocity_SimilarDifferentialValues) {
std::vector<std::pair<std::chrono::nanoseconds, float>> motions = {{1ns, 2.12}, {3ns, 2.12},
{7ns, 2.12}, {8ns, 2.12},
diff --git a/libs/jpegrecoverymap/Android.bp b/libs/jpegrecoverymap/Android.bp
new file mode 100644
index 0000000..285f8d5
--- /dev/null
+++ b/libs/jpegrecoverymap/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_static {
+ name: "libjpegrecoverymap",
+ vendor_available: true,
+
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+
+ srcs: [
+ "recoverymap.cpp",
+ ],
+}
\ No newline at end of file
diff --git a/libs/jpegrecoverymap/OWNERS b/libs/jpegrecoverymap/OWNERS
new file mode 100644
index 0000000..133af5b
--- /dev/null
+++ b/libs/jpegrecoverymap/OWNERS
@@ -0,0 +1,4 @@
+arifdikici@google.com
+deakin@google.com
+dichenzhang@google.com
+kyslov@google.com
\ No newline at end of file
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
new file mode 100644
index 0000000..6949f85
--- /dev/null
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace android::recoverymap {
+
+/*
+ * Holds information for uncompressed image or recovery map.
+ */
+struct jpeg_r_uncompressed_struct {
+ // Pointer to the data location.
+ void* data;
+ // Width of the recovery map or image in pixels.
+ int width;
+ // Height of the recovery map or image in pixels.
+ int height;
+};
+
+/*
+ * Holds information for compressed image or recovery map.
+ */
+struct jpeg_r_compressed_struct {
+ // Pointer to the data location.
+ void* data;
+ // Data length;
+ int length;
+};
+
+typedef struct jpeg_r_uncompressed_struct* j_r_uncompressed_ptr;
+typedef struct jpeg_r_compressed_struct* j_r_compressed_ptr;
+
+class RecoveryMap {
+public:
+ /*
+ * This method is called in the decoding pipeline. It will decode the recovery map.
+ *
+ * @param compressed_recovery_map compressed recovery map
+ * @param dest decoded recover map
+ * @return true if decoding succeeds
+ */
+ bool decodeRecoveryMap(j_r_compressed_ptr compressed_recovery_map,
+ j_r_uncompressed_ptr dest);
+
+ /*
+ * This method is called in the encoding pipeline. It will encode the recovery map.
+ *
+ * @param uncompressed_recovery_map uncompressed recovery map
+ * @param dest encoded recover map
+ * @return true if encoding succeeds
+ */
+ bool encodeRecoveryMap(j_r_uncompressed_ptr uncompressed_recovery_map,
+ j_r_compressed_ptr dest);
+
+ /*
+ * This method is called in the encoding pipeline. It will take the uncompressed 8-bit and
+ * 10-bit yuv images as input, and calculate the uncompressed recovery map.
+ *
+ * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format
+ * @param uncompressed_p010_image uncompressed HDR image in P010 color format
+ * @param dest recover map
+ * @return true if calculation succeeds
+ */
+ bool generateRecoveryMap(j_r_uncompressed_ptr uncompressed_yuv_420_image,
+ j_r_uncompressed_ptr uncompressed_p010_image,
+ j_r_uncompressed_ptr dest);
+
+ /*
+ * This method is called in the decoding pipeline. It will take the uncompressed (decoded)
+ * 8-bit yuv image and the uncompressed (decoded) recovery map as input, and calculate the
+ * 10-bit recovered image (in p010 color format).
+ *
+ * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format
+ * @param uncompressed_recovery_map uncompressed recovery map
+ * @param dest reconstructed HDR image
+ * @return true if calculation succeeds
+ */
+ bool applyRecoveryMap(j_r_uncompressed_ptr uncompressed_yuv_420_image,
+ j_r_uncompressed_ptr uncompressed_recovery_map,
+ j_r_uncompressed_ptr dest);
+
+ /*
+ * This method is called in the decoding pipeline. It will read XMP metadata to find the start
+ * position of the compressed recovery map, and will extract the compressed recovery map.
+ *
+ * @param compressed_jpeg_r_image compressed JPEG_R image
+ * @return compressed recovery map
+ */
+ j_r_compressed_ptr extractRecoveryMap(void* compressed_jpeg_r_image);
+
+ /*
+ * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image
+ * and the compressed recovery map as input, and update the XMP metadata with the end of JPEG
+ * marker, and append the compressed gian map after the JPEG.
+ *
+ * @param compressed_jpeg_image compressed 8-bit JPEG image
+ * @param compress_recovery_map compressed recover map
+ * @return compressed JPEG_R image
+ */
+ void* appendRecoveryMap(void* compressed_jpeg_image,
+ j_r_compressed_ptr compressed_recovery_map);
+};
+
+} // namespace android::recoverymap
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
new file mode 100644
index 0000000..bd92652
--- /dev/null
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jpegrecoverymap/recoverymap.h>
+
+namespace android::recoverymap {
+
+bool RecoveryMap::decodeRecoveryMap(j_r_compressed_ptr compressed_recovery_map,
+ j_r_uncompressed_ptr dest) {
+ if (compressed_recovery_map == nullptr || dest == nullptr) {
+ return false;
+ }
+
+ // TBD
+ return true;
+}
+
+bool RecoveryMap::encodeRecoveryMap(j_r_uncompressed_ptr uncompressed_recovery_map,
+ j_r_compressed_ptr dest) {
+ if (uncompressed_recovery_map == nullptr || dest == nullptr) {
+ return false;
+ }
+
+ // TBD
+ return true;
+}
+
+bool RecoveryMap::generateRecoveryMap(j_r_uncompressed_ptr uncompressed_yuv_420_image,
+ j_r_uncompressed_ptr uncompressed_p010_image,
+ j_r_uncompressed_ptr dest) {
+ if (uncompressed_yuv_420_image == nullptr
+ || uncompressed_p010_image == nullptr
+ || dest == nullptr) {
+ return false;
+ }
+
+ // TBD
+ return true;
+}
+
+bool RecoveryMap::applyRecoveryMap(j_r_uncompressed_ptr uncompressed_yuv_420_image,
+ j_r_uncompressed_ptr uncompressed_recovery_map,
+ j_r_uncompressed_ptr dest) {
+ if (uncompressed_yuv_420_image == nullptr
+ || uncompressed_recovery_map == nullptr
+ || dest == nullptr) {
+ return false;
+ }
+
+ // TBD
+ return true;
+}
+
+j_r_compressed_ptr RecoveryMap::extractRecoveryMap(void* compressed_jpeg_r_image) {
+ if (compressed_jpeg_r_image == nullptr) {
+ return nullptr;
+ }
+
+ // TBD
+ return nullptr;
+}
+
+void* RecoveryMap::appendRecoveryMap(void* compressed_jpeg_image,
+ j_r_compressed_ptr compressed_recovery_map) {
+ if (compressed_jpeg_image == nullptr || compressed_recovery_map == nullptr) {
+ return nullptr;
+ }
+
+ // TBD
+ return nullptr;
+}
+
+} // namespace android::recoverymap
diff --git a/libs/jpegrecoverymap/tests/Android.bp b/libs/jpegrecoverymap/tests/Android.bp
new file mode 100644
index 0000000..79bf723
--- /dev/null
+++ b/libs/jpegrecoverymap/tests/Android.bp
@@ -0,0 +1,33 @@
+// Copyright 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+ name: "libjpegrecoverymap_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "recoverymap_test.cpp",
+ ],
+ static_libs: [
+ "libjpegrecoverymap",
+ ],
+}
\ No newline at end of file
diff --git a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
similarity index 84%
rename from libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
rename to libs/jpegrecoverymap/tests/recoverymap_test.cpp
index 9fac3e8..c436138 100644
--- a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
+++ b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package android.gui;
+#include <jpegrecoverymap/recoverymap.h>
-/** @hide */
-parcelable MirrorSurfaceResult {
- IBinder handle;
- int layerId;
-}
+namespace android {
+
+// Add new tests here.
+} // namespace android
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index 76b85d6..60328e4 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -136,6 +136,7 @@
}
std::vector<DisplayConfigImpl> modesPerDisplay[size];
+ ui::DisplayConnectionType displayConnectionTypes[size];
int numModes = 0;
for (int i = 0; i < size; ++i) {
const sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]);
@@ -145,6 +146,7 @@
status != OK) {
return status;
}
+ displayConnectionTypes[i] = staticInfo.connectionType;
ui::DynamicDisplayInfo dynamicInfo;
if (const status_t status =
@@ -168,8 +170,6 @@
}
}
- const std::optional<PhysicalDisplayId> internalId =
- SurfaceComposerClient::getInternalDisplayId();
ui::Dataspace defaultDataspace;
ui::PixelFormat defaultPixelFormat;
ui::Dataspace wcgDataspace;
@@ -201,8 +201,9 @@
for (size_t i = 0; i < size; ++i) {
const PhysicalDisplayId id = ids[i];
- const ADisplayType type = (internalId == id) ? ADisplayType::DISPLAY_TYPE_INTERNAL
- : ADisplayType::DISPLAY_TYPE_EXTERNAL;
+ const ADisplayType type = (displayConnectionTypes[i] == ui::DisplayConnectionType::Internal)
+ ? ADisplayType::DISPLAY_TYPE_INTERNAL
+ : ADisplayType::DISPLAY_TYPE_EXTERNAL;
const std::vector<DisplayConfigImpl>& configs = modesPerDisplay[i];
memcpy(configData, configs.data(), sizeof(DisplayConfigImpl) * configs.size());
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 79f49e1..c7745e6 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -235,8 +235,8 @@
NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
- NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
- NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+ /* 28, removed: NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT */
+ /* 29, removed: NATIVE_WINDOW_GET_HDR_SUPPORT */
NATIVE_WINDOW_SET_USAGE64 = ANATIVEWINDOW_PERFORM_SET_USAGE64,
NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
@@ -988,15 +988,34 @@
outDequeueReadyTime, outReleaseTime);
}
-static inline int native_window_get_wide_color_support(
- struct ANativeWindow* window, bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
- outSupport);
+/* deprecated. Always returns 0 and outSupport holds true. Don't call. */
+static inline int native_window_get_wide_color_support (
+ struct ANativeWindow* window __UNUSED, bool* outSupport) __deprecated;
+
+/*
+ Deprecated(b/242763577): to be removed, this method should not be used
+ Surface support should not be tied to the display
+ Return true since most displays should have this support
+*/
+static inline int native_window_get_wide_color_support (
+ struct ANativeWindow* window __UNUSED, bool* outSupport) {
+ *outSupport = true;
+ return 0;
}
-static inline int native_window_get_hdr_support(struct ANativeWindow* window,
+/* deprecated. Always returns 0 and outSupport holds true. Don't call. */
+static inline int native_window_get_hdr_support(struct ANativeWindow* window __UNUSED,
+ bool* outSupport) __deprecated;
+
+/*
+ Deprecated(b/242763577): to be removed, this method should not be used
+ Surface support should not be tied to the display
+ Return true since most displays should have this support
+*/
+static inline int native_window_get_hdr_support(struct ANativeWindow* window __UNUSED,
bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+ *outSupport = true;
+ return 0;
}
static inline int native_window_get_consumer_usage(struct ANativeWindow* window,
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 739f3fa..d44eb46 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -80,16 +80,26 @@
std::once_flag once;
std::call_once(once, []() {
auto surfaceComposerClient = SurfaceComposerClient::getDefault();
- auto displayToken = surfaceComposerClient->getInternalDisplayToken();
- ui::DisplayMode displayMode;
- if (surfaceComposerClient->getActiveDisplayMode(displayToken, &displayMode) < 0) {
- LOG_ALWAYS_FATAL("Failed to get active display mode!");
+ auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ LOG_ALWAYS_FATAL_IF(ids.empty(), "Failed to get any display!");
+ ui::Size resolution = ui::kEmptySize;
+ // find the largest display resolution
+ for (auto id : ids) {
+ auto displayToken = surfaceComposerClient->getPhysicalDisplayToken(id);
+ ui::DisplayMode displayMode;
+ if (surfaceComposerClient->getActiveDisplayMode(displayToken, &displayMode) < 0) {
+ LOG_ALWAYS_FATAL("Failed to get active display mode!");
+ }
+ auto tw = displayMode.resolution.width;
+ auto th = displayMode.resolution.height;
+ LOG_ALWAYS_FATAL_IF(tw <= 0 || th <= 0, "Invalid display size!");
+ if (resolution.width * resolution.height <
+ displayMode.resolution.width * displayMode.resolution.height) {
+ resolution = displayMode.resolution;
+ }
}
- auto w = displayMode.resolution.width;
- auto h = displayMode.resolution.height;
- LOG_ALWAYS_FATAL_IF(w <= 0 || h <= 0, "Invalid display size!");
- width = static_cast<uint32_t>(w);
- height = static_cast<uint32_t>(h);
+ width = static_cast<uint32_t>(resolution.width);
+ height = static_cast<uint32_t>(resolution.height);
});
return std::pair<uint32_t, uint32_t>(width, height);
}
diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp
index 3306012..6ae27de 100644
--- a/libs/ui/DeviceProductInfo.cpp
+++ b/libs/ui/DeviceProductInfo.cpp
@@ -14,44 +14,43 @@
* limitations under the License.
*/
+#include <ftl/match.h>
#include <ui/DeviceProductInfo.h>
#include <android-base/stringprintf.h>
-#include <utils/Log.h>
-
-#define RETURN_IF_ERROR(op) \
- if (const status_t status = (op); status != OK) return status;
namespace android {
-using base::StringAppendF;
+std::string to_string(const DeviceProductInfo& info) {
+ using base::StringAppendF;
-void DeviceProductInfo::dump(std::string& result) const {
- StringAppendF(&result, "{name=\"%s\", ", name.c_str());
- StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data());
- StringAppendF(&result, "productId=%s, ", productId.c_str());
+ std::string result;
+ StringAppendF(&result, "{name=\"%s\", ", info.name.c_str());
+ StringAppendF(&result, "manufacturerPnpId=%s, ", info.manufacturerPnpId.data());
+ StringAppendF(&result, "productId=%s, ", info.productId.c_str());
- if (const auto* model = std::get_if<ModelYear>(&manufactureOrModelDate)) {
- StringAppendF(&result, "modelYear=%u, ", model->year);
- } else if (const auto* manufactureWeekAndYear =
- std::get_if<ManufactureWeekAndYear>(&manufactureOrModelDate)) {
- StringAppendF(&result, "manufactureWeek=%u, ", manufactureWeekAndYear->week);
- StringAppendF(&result, "manufactureYear=%d, ", manufactureWeekAndYear->year);
- } else if (const auto* manufactureYear =
- std::get_if<ManufactureYear>(&manufactureOrModelDate)) {
- StringAppendF(&result, "manufactureYear=%d, ", manufactureYear->year);
- } else {
- ALOGE("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
- }
+ ftl::match(
+ info.manufactureOrModelDate,
+ [&](DeviceProductInfo::ModelYear model) {
+ StringAppendF(&result, "modelYear=%u, ", model.year);
+ },
+ [&](DeviceProductInfo::ManufactureWeekAndYear manufacture) {
+ StringAppendF(&result, "manufactureWeek=%u, ", manufacture.week);
+ StringAppendF(&result, "manufactureYear=%d, ", manufacture.year);
+ },
+ [&](DeviceProductInfo::ManufactureYear manufacture) {
+ StringAppendF(&result, "manufactureYear=%d, ", manufacture.year);
+ });
result.append("relativeAddress=[");
- for (size_t i = 0; i < relativeAddress.size(); i++) {
+ for (size_t i = 0; i < info.relativeAddress.size(); i++) {
if (i != 0) {
result.append(", ");
}
- StringAppendF(&result, "%u", relativeAddress[i]);
+ StringAppendF(&result, "%u", info.relativeAddress[i]);
}
result.append("]}");
+ return result;
}
} // namespace android
diff --git a/libs/ui/include/ui/ColorMode.h b/libs/ui/include/ui/ColorMode.h
new file mode 100644
index 0000000..a47eaed
--- /dev/null
+++ b/libs/ui/include/ui/ColorMode.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <ui/GraphicTypes.h>
+
+namespace android::ui {
+
+using ColorModes = std::vector<ColorMode>;
+
+inline bool isWideColorMode(ColorMode colorMode) {
+ switch (colorMode) {
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::ADOBE_RGB:
+ case ColorMode::DCI_P3:
+ case ColorMode::BT2020:
+ case ColorMode::DISPLAY_BT2020:
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ return true;
+ case ColorMode::NATIVE:
+ case ColorMode::STANDARD_BT601_625:
+ case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+ case ColorMode::STANDARD_BT601_525:
+ case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+ case ColorMode::STANDARD_BT709:
+ case ColorMode::SRGB:
+ return false;
+ }
+}
+
+inline Dataspace pickDataspaceFor(ColorMode colorMode) {
+ switch (colorMode) {
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ case ColorMode::DISPLAY_BT2020:
+ return Dataspace::DISPLAY_P3;
+ default:
+ return Dataspace::V0_SRGB;
+ }
+}
+
+} // namespace android::ui
diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h
index 879e46f..4229cf1 100644
--- a/libs/ui/include/ui/DeviceProductInfo.h
+++ b/libs/ui/include/ui/DeviceProductInfo.h
@@ -61,8 +61,8 @@
// address is unavailable.
// For example, for HDMI connected device this will be the physical address.
std::vector<uint8_t> relativeAddress;
-
- void dump(std::string& result) const;
};
+std::string to_string(const DeviceProductInfo&);
+
} // namespace android
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
index d38f2ef..f1122fd 100644
--- a/opengl/libs/EGL/egl_angle_platform.cpp
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -68,9 +68,9 @@
static TraceEventHandle addTraceEvent(
PlatformMethods* /**platform*/, char phase, const unsigned char* /*category_group_enabled*/,
- const char* name, unsigned long long /*id*/, double /*timestamp*/, int /*num_args*/,
- const char** /*arg_names*/, const unsigned char* /*arg_types*/,
- const unsigned long long* /*arg_values*/, unsigned char /*flags*/) {
+ const char* name, unsigned long long /*id*/, double /*timestamp*/, int num_args,
+ const char** arg_names, const unsigned char* /*arg_types*/,
+ const unsigned long long* arg_values, unsigned char /*flags*/) {
switch (phase) {
case 'B': {
ATRACE_BEGIN(name);
@@ -84,6 +84,13 @@
ATRACE_NAME(name);
break;
}
+ case 'C': {
+ for(int i=0; i<num_args ; i++)
+ {
+ ATRACE_INT(arg_names[i],arg_values[i]);
+ }
+ break;
+ }
default:
// Could handle other event types here
break;
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index fd4522e..e94b565 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -36,7 +36,14 @@
return;
}
- const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ if (ids.empty()) {
+ fprintf(stderr, "Failed to get ID for any displays.\n");
+ return;
+ }
+
+ // display 0 is picked for now, can extend to support all displays if needed
+ const auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
if (displayToken == nullptr) {
fprintf(stderr, "ERROR: no display\n");
return;
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 88a9acb..ddcd51f 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -85,12 +85,12 @@
"libstatspull",
"libstatssocket",
"libutils",
- "libui",
"server_configurable_flags",
],
static_libs: [
"libattestation",
"libpalmrejection",
+ "libui-types",
],
}
@@ -139,6 +139,7 @@
"InputListener.cpp",
"InputReaderBase.cpp",
"InputThread.cpp",
+ "NotifyArgs.cpp",
"VibrationElement.cpp",
],
}
@@ -152,7 +153,6 @@
"libcutils",
"libinput",
"liblog",
- "libui",
"libutils",
],
header_libs: [
diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp
index 8aee39f..23b6f57 100644
--- a/services/inputflinger/InputCommonConverter.cpp
+++ b/services/inputflinger/InputCommonConverter.cpp
@@ -263,6 +263,8 @@
static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14);
static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15);
static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE) ==
+ static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_16));
static common::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) {
common::VideoFrame out;
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 54d0e02..d33b298 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -31,206 +31,11 @@
namespace android {
-// --- NotifyConfigurationChangedArgs ---
-
-NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime)
- : id(id), eventTime(eventTime) {}
-
-// --- NotifyKeyArgs ---
-
-NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId,
- uint32_t source, int32_t displayId, uint32_t policyFlags,
- int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
- int32_t metaState, nsecs_t downTime)
- : id(id),
- eventTime(eventTime),
- deviceId(deviceId),
- source(source),
- displayId(displayId),
- policyFlags(policyFlags),
- action(action),
- flags(flags),
- keyCode(keyCode),
- scanCode(scanCode),
- metaState(metaState),
- downTime(downTime),
- readTime(readTime) {}
-
-// --- NotifyMotionArgs ---
-
-NotifyMotionArgs::NotifyMotionArgs(
- int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
- int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
- float xCursorPosition, float yCursorPosition, nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames)
- : id(id),
- eventTime(eventTime),
- deviceId(deviceId),
- source(source),
- displayId(displayId),
- policyFlags(policyFlags),
- action(action),
- actionButton(actionButton),
- flags(flags),
- metaState(metaState),
- buttonState(buttonState),
- classification(classification),
- edgeFlags(edgeFlags),
- pointerCount(pointerCount),
- xPrecision(xPrecision),
- yPrecision(yPrecision),
- xCursorPosition(xCursorPosition),
- yCursorPosition(yCursorPosition),
- downTime(downTime),
- readTime(readTime),
- videoFrames(videoFrames) {
- for (uint32_t i = 0; i < pointerCount; i++) {
- this->pointerProperties[i].copyFrom(pointerProperties[i]);
- this->pointerCoords[i].copyFrom(pointerCoords[i]);
- }
+std::list<NotifyArgs>& operator+=(std::list<NotifyArgs>& keep, std::list<NotifyArgs>&& consume) {
+ keep.splice(keep.end(), consume);
+ return keep;
}
-NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other)
- : id(other.id),
- eventTime(other.eventTime),
- deviceId(other.deviceId),
- source(other.source),
- displayId(other.displayId),
- policyFlags(other.policyFlags),
- action(other.action),
- actionButton(other.actionButton),
- flags(other.flags),
- metaState(other.metaState),
- buttonState(other.buttonState),
- classification(other.classification),
- edgeFlags(other.edgeFlags),
- pointerCount(other.pointerCount),
- xPrecision(other.xPrecision),
- yPrecision(other.yPrecision),
- xCursorPosition(other.xCursorPosition),
- yCursorPosition(other.yCursorPosition),
- downTime(other.downTime),
- readTime(other.readTime),
- videoFrames(other.videoFrames) {
- for (uint32_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].copyFrom(other.pointerProperties[i]);
- pointerCoords[i].copyFrom(other.pointerCoords[i]);
- }
-}
-
-static inline bool isCursorPositionEqual(float lhs, float rhs) {
- return (isnan(lhs) && isnan(rhs)) || lhs == rhs;
-}
-
-bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const {
- bool equal = id == rhs.id && eventTime == rhs.eventTime && readTime == rhs.readTime &&
- deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId &&
- policyFlags == rhs.policyFlags && action == rhs.action &&
- actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState &&
- buttonState == rhs.buttonState && classification == rhs.classification &&
- edgeFlags == rhs.edgeFlags &&
- pointerCount == rhs.pointerCount
- // PointerProperties and PointerCoords are compared separately below
- && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision &&
- isCursorPositionEqual(xCursorPosition, rhs.xCursorPosition) &&
- isCursorPositionEqual(yCursorPosition, rhs.yCursorPosition) &&
- downTime == rhs.downTime && videoFrames == rhs.videoFrames;
- if (!equal) {
- return false;
- }
-
- for (size_t i = 0; i < pointerCount; i++) {
- equal =
- pointerProperties[i] == rhs.pointerProperties[i]
- && pointerCoords[i] == rhs.pointerCoords[i];
- if (!equal) {
- return false;
- }
- }
- return true;
-}
-
-std::string NotifyMotionArgs::dump() const {
- std::string coords;
- for (uint32_t i = 0; i < pointerCount; i++) {
- if (!coords.empty()) {
- coords += ", ";
- }
- coords += StringPrintf("{%" PRIu32 ": ", i);
- coords +=
- StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f pressure=%.1f", pointerProperties[i].id,
- pointerCoords[i].getX(), pointerCoords[i].getY(),
- pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
- const int32_t toolType = pointerProperties[i].toolType;
- if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) {
- coords += StringPrintf(" toolType=%s", motionToolTypeToString(toolType));
- }
- const float major = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
- const float minor = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
- const float orientation = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
- if (major != 0 || minor != 0) {
- coords += StringPrintf(" major=%.1f minor=%.1f orientation=%.1f", major, minor,
- orientation);
- }
- coords += "}";
- }
- return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32
- ", source=%s, action=%s, pointerCount=%" PRIu32
- " pointers=%s, flags=0x%08x)",
- id, eventTime, deviceId, inputEventSourceToString(source).c_str(),
- MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str(),
- flags);
-}
-
-// --- NotifySwitchArgs ---
-
-NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags,
- uint32_t switchValues, uint32_t switchMask)
- : id(id),
- eventTime(eventTime),
- policyFlags(policyFlags),
- switchValues(switchValues),
- switchMask(switchMask) {}
-
-// --- NotifySensorArgs ---
-
-NotifySensorArgs::NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
- InputDeviceSensorType sensorType,
- InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
- nsecs_t hwTimestamp, std::vector<float> values)
- : id(id),
- eventTime(eventTime),
- deviceId(deviceId),
- source(source),
- sensorType(sensorType),
- accuracy(accuracy),
- accuracyChanged(accuracyChanged),
- hwTimestamp(hwTimestamp),
- values(std::move(values)) {}
-
-// --- NotifyVibratorStateArgs ---
-
-NotifyVibratorStateArgs::NotifyVibratorStateArgs(int32_t id, nsecs_t eventTime, int32_t deviceId,
- bool isOn)
- : id(id), eventTime(eventTime), deviceId(deviceId), isOn(isOn) {}
-
-NotifyVibratorStateArgs::NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other)
- : id(other.id), eventTime(other.eventTime), deviceId(other.deviceId), isOn(other.isOn) {}
-
-// --- NotifyDeviceResetArgs ---
-
-NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId)
- : id(id), eventTime(eventTime), deviceId(deviceId) {}
-
-// --- NotifyPointerCaptureChangedArgs ---
-
-NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(
- int32_t id, nsecs_t eventTime, const PointerCaptureRequest& request)
- : id(id), eventTime(eventTime), request(request) {}
-
// --- InputListenerInterface ---
// Helper to std::visit with lambdas.
diff --git a/services/inputflinger/NotifyArgs.cpp b/services/inputflinger/NotifyArgs.cpp
new file mode 100644
index 0000000..b192ad7
--- /dev/null
+++ b/services/inputflinger/NotifyArgs.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NotifyArgs"
+
+#define ATRACE_TAG ATRACE_TAG_INPUT
+
+#include "NotifyArgs.h"
+
+#include <android-base/stringprintf.h>
+#include <android/log.h>
+#include <math.h>
+#include <utils/Trace.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+// --- NotifyConfigurationChangedArgs ---
+
+NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime)
+ : id(id), eventTime(eventTime) {}
+
+// --- NotifyKeyArgs ---
+
+NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId,
+ uint32_t source, int32_t displayId, uint32_t policyFlags,
+ int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
+ int32_t metaState, nsecs_t downTime)
+ : id(id),
+ eventTime(eventTime),
+ deviceId(deviceId),
+ source(source),
+ displayId(displayId),
+ policyFlags(policyFlags),
+ action(action),
+ flags(flags),
+ keyCode(keyCode),
+ scanCode(scanCode),
+ metaState(metaState),
+ downTime(downTime),
+ readTime(readTime) {}
+
+// --- NotifyMotionArgs ---
+
+NotifyMotionArgs::NotifyMotionArgs(
+ int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId, uint32_t source,
+ int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
+ int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
+ int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
+ float xCursorPosition, float yCursorPosition, nsecs_t downTime,
+ const std::vector<TouchVideoFrame>& videoFrames)
+ : id(id),
+ eventTime(eventTime),
+ deviceId(deviceId),
+ source(source),
+ displayId(displayId),
+ policyFlags(policyFlags),
+ action(action),
+ actionButton(actionButton),
+ flags(flags),
+ metaState(metaState),
+ buttonState(buttonState),
+ classification(classification),
+ edgeFlags(edgeFlags),
+ pointerCount(pointerCount),
+ xPrecision(xPrecision),
+ yPrecision(yPrecision),
+ xCursorPosition(xCursorPosition),
+ yCursorPosition(yCursorPosition),
+ downTime(downTime),
+ readTime(readTime),
+ videoFrames(videoFrames) {
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ this->pointerProperties[i].copyFrom(pointerProperties[i]);
+ this->pointerCoords[i].copyFrom(pointerCoords[i]);
+ }
+}
+
+NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other)
+ : id(other.id),
+ eventTime(other.eventTime),
+ deviceId(other.deviceId),
+ source(other.source),
+ displayId(other.displayId),
+ policyFlags(other.policyFlags),
+ action(other.action),
+ actionButton(other.actionButton),
+ flags(other.flags),
+ metaState(other.metaState),
+ buttonState(other.buttonState),
+ classification(other.classification),
+ edgeFlags(other.edgeFlags),
+ pointerCount(other.pointerCount),
+ xPrecision(other.xPrecision),
+ yPrecision(other.yPrecision),
+ xCursorPosition(other.xCursorPosition),
+ yCursorPosition(other.yCursorPosition),
+ downTime(other.downTime),
+ readTime(other.readTime),
+ videoFrames(other.videoFrames) {
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].copyFrom(other.pointerProperties[i]);
+ pointerCoords[i].copyFrom(other.pointerCoords[i]);
+ }
+}
+
+static inline bool isCursorPositionEqual(float lhs, float rhs) {
+ return (isnan(lhs) && isnan(rhs)) || lhs == rhs;
+}
+
+bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const {
+ bool equal = id == rhs.id && eventTime == rhs.eventTime && readTime == rhs.readTime &&
+ deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId &&
+ policyFlags == rhs.policyFlags && action == rhs.action &&
+ actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState &&
+ buttonState == rhs.buttonState && classification == rhs.classification &&
+ edgeFlags == rhs.edgeFlags &&
+ pointerCount == rhs.pointerCount
+ // PointerProperties and PointerCoords are compared separately below
+ && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision &&
+ isCursorPositionEqual(xCursorPosition, rhs.xCursorPosition) &&
+ isCursorPositionEqual(yCursorPosition, rhs.yCursorPosition) &&
+ downTime == rhs.downTime && videoFrames == rhs.videoFrames;
+ if (!equal) {
+ return false;
+ }
+
+ for (size_t i = 0; i < pointerCount; i++) {
+ equal = pointerProperties[i] == rhs.pointerProperties[i] &&
+ pointerCoords[i] == rhs.pointerCoords[i];
+ if (!equal) {
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string NotifyMotionArgs::dump() const {
+ std::string coords;
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ if (!coords.empty()) {
+ coords += ", ";
+ }
+ coords += StringPrintf("{%" PRIu32 ": ", i);
+ coords +=
+ StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f pressure=%.1f", pointerProperties[i].id,
+ pointerCoords[i].getX(), pointerCoords[i].getY(),
+ pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+ const int32_t toolType = pointerProperties[i].toolType;
+ if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) {
+ coords += StringPrintf(" toolType=%s", motionToolTypeToString(toolType));
+ }
+ const float major = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
+ const float minor = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
+ const float orientation = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+ if (major != 0 || minor != 0) {
+ coords += StringPrintf(" major=%.1f minor=%.1f orientation=%.1f", major, minor,
+ orientation);
+ }
+ coords += "}";
+ }
+ return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32
+ ", source=%s, action=%s, pointerCount=%" PRIu32
+ " pointers=%s, flags=0x%08x)",
+ id, eventTime, deviceId, inputEventSourceToString(source).c_str(),
+ MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str(),
+ flags);
+}
+
+// --- NotifySwitchArgs ---
+
+NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags,
+ uint32_t switchValues, uint32_t switchMask)
+ : id(id),
+ eventTime(eventTime),
+ policyFlags(policyFlags),
+ switchValues(switchValues),
+ switchMask(switchMask) {}
+
+// --- NotifySensorArgs ---
+
+NotifySensorArgs::NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+ InputDeviceSensorType sensorType,
+ InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
+ nsecs_t hwTimestamp, std::vector<float> values)
+ : id(id),
+ eventTime(eventTime),
+ deviceId(deviceId),
+ source(source),
+ sensorType(sensorType),
+ accuracy(accuracy),
+ accuracyChanged(accuracyChanged),
+ hwTimestamp(hwTimestamp),
+ values(std::move(values)) {}
+
+// --- NotifyVibratorStateArgs ---
+
+NotifyVibratorStateArgs::NotifyVibratorStateArgs(int32_t id, nsecs_t eventTime, int32_t deviceId,
+ bool isOn)
+ : id(id), eventTime(eventTime), deviceId(deviceId), isOn(isOn) {}
+
+// --- NotifyDeviceResetArgs ---
+
+NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId)
+ : id(id), eventTime(eventTime), deviceId(deviceId) {}
+
+// --- NotifyPointerCaptureChangedArgs ---
+
+NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(
+ int32_t id, nsecs_t eventTime, const PointerCaptureRequest& request)
+ : id(id), eventTime(eventTime), request(request) {}
+
+// Helper to std::visit with lambdas.
+template <typename... V>
+struct Visitor : V... {};
+// explicit deduction guide (not needed as of C++20)
+template <typename... V>
+Visitor(V...) -> Visitor<V...>;
+
+const char* toString(const NotifyArgs& args) {
+ Visitor toStringVisitor{
+ [&](const NotifyConfigurationChangedArgs&) { return "NotifyConfigurationChangedArgs"; },
+ [&](const NotifyKeyArgs&) { return "NotifyKeyArgs"; },
+ [&](const NotifyMotionArgs&) { return "NotifyMotionArgs"; },
+ [&](const NotifySensorArgs&) { return "NotifySensorArgs"; },
+ [&](const NotifySwitchArgs&) { return "NotifySwitchArgs"; },
+ [&](const NotifyDeviceResetArgs&) { return "NotifyDeviceResetArgs"; },
+ [&](const NotifyPointerCaptureChangedArgs&) {
+ return "NotifyPointerCaptureChangedArgs";
+ },
+ [&](const NotifyVibratorStateArgs&) { return "NotifyVibratorStateArgs"; },
+ };
+ return std::visit(toStringVisitor, args);
+}
+
+} // namespace android
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index 75071d5..e5c19af 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -26,7 +26,6 @@
"libinputreporter",
"liblog",
"libstatslog",
- "libui",
"libutils",
],
static_libs: [
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 12eeea6..3d4dd7e 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -112,8 +112,6 @@
void notifyDropWindow(const sp<IBinder>&, float x, float y) override {}
- bool isPerDisplayTouchModeEnabled() override { return false; }
-
InputDispatcherConfiguration mConfig;
};
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index cdad9c9..eb79b76 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -63,7 +63,6 @@
"libstatslog",
"libstatspull",
"libstatssocket",
- "libui",
"libgui",
"libutils",
"server_configurable_flags",
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 8046bbe..33e7e17 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -195,9 +195,10 @@
// --- TouchModeEntry ---
-TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode)
+TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int displayId)
: EventEntry(id, Type::TOUCH_MODE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER),
- inTouchMode(inTouchMode) {}
+ inTouchMode(inTouchMode),
+ displayId(displayId) {}
TouchModeEntry::~TouchModeEntry() {}
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 1f916f3..60f319a 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -210,8 +210,9 @@
struct TouchModeEntry : EventEntry {
bool inTouchMode;
+ int32_t displayId;
- TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode);
+ TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int32_t displayId);
std::string getDescription() const override;
~TouchModeEntry() override;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ff63a6f..a793f57 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -524,6 +524,21 @@
return {};
}
+Point resolveTouchedPosition(const MotionEntry& entry) {
+ const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
+ // Always dispatch mouse events to cursor position.
+ if (isFromMouse) {
+ return Point(static_cast<int32_t>(entry.xCursorPosition),
+ static_cast<int32_t>(entry.yCursorPosition));
+ }
+
+ const int32_t pointerIndex = getMotionEventActionPointerIndex(entry.action);
+ return Point(static_cast<int32_t>(
+ entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X)),
+ static_cast<int32_t>(
+ entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)));
+}
+
} // namespace
// --- InputDispatcher ---
@@ -544,17 +559,12 @@
mDispatchEnabled(false),
mDispatchFrozen(false),
mInputFilterEnabled(false),
- // 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(kDefaultInTouchMode),
mMaximumObscuringOpacityForTouch(1.0f),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
mStaleEventTimeout(staleEventTimeout),
mLatencyAggregator(),
- mLatencyTracker(&mLatencyAggregator),
- kPerDisplayTouchModeEnabled(mPolicy->isPerDisplayTouchModeEnabled()) {
+ mLatencyTracker(&mLatencyAggregator) {
mLooper = sp<Looper>::make(false);
mReporter = createInputReporter();
@@ -562,7 +572,6 @@
SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
mKeyRepeatState.lastKeyEntry = nullptr;
-
policy->getDispatcherConfiguration(&mConfig);
}
@@ -927,13 +936,10 @@
// If the application takes too long to catch up then we drop all events preceding
// the touch into the other window.
if (isPointerDownEvent && mAwaitedFocusedApplication != nullptr) {
- int32_t displayId = motionEntry.displayId;
- int32_t x = static_cast<int32_t>(
- motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = static_cast<int32_t>(
- motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
-
+ const int32_t displayId = motionEntry.displayId;
+ const auto [x, y] = resolveTouchedPosition(motionEntry);
const bool isStylus = isPointerFromStylus(motionEntry, 0 /*pointerIndex*/);
+
sp<WindowInfoHandle> touchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, nullptr, isStylus);
if (touchedWindowHandle != nullptr &&
@@ -1435,7 +1441,7 @@
void InputDispatcher::dispatchTouchModeChangeLocked(nsecs_t currentTime,
const std::shared_ptr<TouchModeEntry>& entry) {
const std::vector<sp<WindowInfoHandle>>& windowHandles =
- getWindowHandlesLocked(mFocusedDisplayId);
+ getWindowHandlesLocked(entry->displayId);
if (windowHandles.empty()) {
return;
}
@@ -1452,7 +1458,6 @@
const std::vector<sp<WindowInfoHandle>>& windowHandles) const {
std::vector<InputTarget> inputTargets;
for (const sp<WindowInfoHandle>& handle : windowHandles) {
- // TODO(b/193718270): Due to performance concerns, consider notifying visible windows only.
const sp<IBinder>& token = handle->getToken();
if (token == nullptr) {
continue;
@@ -2074,18 +2079,8 @@
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
-
- int32_t x;
- int32_t y;
+ const auto [x, y] = resolveTouchedPosition(entry);
const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- // Always dispatch mouse events to cursor position.
- if (isFromMouse) {
- x = int32_t(entry.xCursorPosition);
- y = int32_t(entry.yCursorPosition);
- } else {
- x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
- y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
- }
const bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
const bool isStylus = isPointerFromStylus(entry, pointerIndex);
newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
@@ -2148,43 +2143,7 @@
}
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
- const WindowInfo& info = *windowHandle->getInfo();
-
- // Skip spy window targets that are not valid for targeted injection.
- if (const auto err = verifyTargetedInjection(windowHandle, entry); err) {
- continue;
- }
-
- if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
- ALOGI("Not sending touch event to %s because it is paused",
- windowHandle->getName().c_str());
- continue;
- }
-
- // Ensure the window has a connection and the connection is responsive
- const bool isResponsive = hasResponsiveConnectionLocked(*windowHandle);
- if (!isResponsive) {
- ALOGW("Not sending touch gesture to %s because it is not responsive",
- windowHandle->getName().c_str());
- continue;
- }
-
- // Drop events that can't be trusted due to occlusion
- TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(windowHandle, x, y);
- if (!isTouchTrustedLocked(occlusionInfo)) {
- if (DEBUG_TOUCH_OCCLUSION) {
- ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
- for (const auto& log : occlusionInfo.debugInfo) {
- ALOGD("%s", log.c_str());
- }
- }
- ALOGW("Dropping untrusted touch event due to %s/%d",
- occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
- continue;
- }
-
- // Drop touch events if requested by input feature
- if (shouldDropInput(entry, windowHandle)) {
+ if (!canWindowReceiveMotionLocked(windowHandle, entry)) {
continue;
}
@@ -2240,9 +2199,7 @@
// Check whether touches should slip outside of the current foreground window.
if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.pointerCount == 1 &&
tempTouchState.isSlippery()) {
- const int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- const int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
-
+ const auto [x, y] = resolveTouchedPosition(entry);
const bool isStylus = isPointerFromStylus(entry, 0 /*pointerIndex*/);
sp<WindowInfoHandle> oldTouchedWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
@@ -4614,26 +4571,58 @@
return getWindowHandleLocked(focusedToken, displayId);
}
-bool InputDispatcher::hasResponsiveConnectionLocked(WindowInfoHandle& windowHandle) const {
- sp<Connection> connection = getConnectionLocked(windowHandle.getToken());
- const bool noInputChannel =
- windowHandle.getInfo()->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);
- if (connection != nullptr && noInputChannel) {
- ALOGW("%s has feature NO_INPUT_CHANNEL, but it matched to connection %s",
- windowHandle.getName().c_str(), connection->inputChannel->getName().c_str());
+bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& window,
+ const MotionEntry& motionEntry) const {
+ const WindowInfo& info = *window->getInfo();
+
+ // Skip spy window targets that are not valid for targeted injection.
+ if (const auto err = verifyTargetedInjection(window, motionEntry); err) {
return false;
}
+ if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
+ ALOGI("Not sending touch event to %s because it is paused", window->getName().c_str());
+ return false;
+ }
+
+ if (info.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
+ ALOGW("Not sending touch gesture to %s because it has config NO_INPUT_CHANNEL",
+ window->getName().c_str());
+ return false;
+ }
+
+ sp<Connection> connection = getConnectionLocked(window->getToken());
if (connection == nullptr) {
- if (!noInputChannel) {
- ALOGI("Could not find connection for %s", windowHandle.getName().c_str());
- }
+ ALOGW("Not sending touch to %s because there's no corresponding connection",
+ window->getName().c_str());
return false;
}
+
if (!connection->responsive) {
- ALOGW("Window %s is not responsive", windowHandle.getName().c_str());
+ ALOGW("Not sending touch to %s because it is not responsive", window->getName().c_str());
return false;
}
+
+ // Drop events that can't be trusted due to occlusion
+ const auto [x, y] = resolveTouchedPosition(motionEntry);
+ TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(window, x, y);
+ if (!isTouchTrustedLocked(occlusionInfo)) {
+ if (DEBUG_TOUCH_OCCLUSION) {
+ ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
+ for (const auto& log : occlusionInfo.debugInfo) {
+ ALOGD("%s", log.c_str());
+ }
+ }
+ ALOGW("Dropping untrusted touch event due to %s/%d", occlusionInfo.obscuringPackage.c_str(),
+ occlusionInfo.obscuringUid);
+ return false;
+ }
+
+ // Drop touch events if requested by input feature
+ if (shouldDropInput(motionEntry, window)) {
+ return false;
+ }
+
return true;
}
@@ -5012,15 +5001,20 @@
bool needWake = false;
{
std::scoped_lock lock(mLock);
- if (mInTouchMode == inTouchMode) {
+ ALOGD_IF(DEBUG_TOUCH_MODE,
+ "Request to change touch mode to %s (calling pid=%d, uid=%d, "
+ "hasPermission=%s, target displayId=%d, mTouchModePerDisplay[displayId]=%s)",
+ toString(inTouchMode), pid, uid, toString(hasPermission), displayId,
+ mTouchModePerDisplay.count(displayId) == 0
+ ? "not set"
+ : std::to_string(mTouchModePerDisplay[displayId]).c_str());
+
+ // TODO(b/198499018): Ensure that WM can guarantee that touch mode is properly set when
+ // display is created.
+ auto touchModeIt = mTouchModePerDisplay.find(displayId);
+ if (touchModeIt != mTouchModePerDisplay.end() && touchModeIt->second == inTouchMode) {
return false;
}
- if (DEBUG_TOUCH_MODE) {
- ALOGD("Request to change touch mode from %s to %s (calling pid=%d, uid=%d, "
- "hasPermission=%s, target displayId=%d, perDisplayTouchModeEnabled=%s)",
- toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission),
- displayId, toString(kPerDisplayTouchModeEnabled));
- }
if (!hasPermission) {
if (!focusedWindowIsOwnedByLocked(pid, uid) &&
!recentWindowsAreOwnedByLocked(pid, uid)) {
@@ -5030,11 +5024,9 @@
return false;
}
}
-
- // TODO(b/198499018): Store touch mode per display (kPerDisplayTouchModeEnabled)
- mInTouchMode = inTouchMode;
-
- auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode);
+ mTouchModePerDisplay[displayId] = inTouchMode;
+ auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode,
+ displayId);
needWake = enqueueInboundEventLocked(std::move(entry));
} // release lock
@@ -5474,6 +5466,16 @@
dump += INDENT "AppSwitch: not pending\n";
}
+ if (!mTouchModePerDisplay.empty()) {
+ dump += INDENT "TouchModePerDisplay:\n";
+ for (const auto& [displayId, touchMode] : mTouchModePerDisplay) {
+ dump += StringPrintf(INDENT2 "Display: %" PRId32 " TouchMode: %s\n", displayId,
+ std::to_string(touchMode).c_str());
+ }
+ } else {
+ dump += INDENT "TouchModePerDisplay: <none>\n";
+ }
+
dump += INDENT "Configuration:\n";
dump += StringPrintf(INDENT2 "KeyRepeatDelay: %" PRId64 "ms\n", ns2ms(mConfig.keyRepeatDelay));
dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %" PRId64 "ms\n",
@@ -6366,6 +6368,8 @@
mFocusResolver.displayRemoved(displayId);
// Reset pointer capture eligibility, regardless of previous state.
std::erase(mIneligibleDisplaysForPointerCapture, displayId);
+ // Remove the associated touch mode state.
+ mTouchModePerDisplay.erase(displayId);
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index b5bbce8..14b046a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -41,7 +41,6 @@
#include <input/InputTransport.h>
#include <limits.h>
#include <stddef.h>
-#include <ui/Region.h>
#include <unistd.h>
#include <utils/BitSet.h>
#include <utils/Looper.h>
@@ -343,9 +342,13 @@
bool mDispatchEnabled GUARDED_BY(mLock);
bool mDispatchFrozen GUARDED_BY(mLock);
bool mInputFilterEnabled GUARDED_BY(mLock);
- bool mInTouchMode GUARDED_BY(mLock);
float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock);
+ // This map is not really needed, but it helps a lot with debugging (dumpsys input).
+ // In the java layer, touch mode states are spread across multiple DisplayContent objects,
+ // making harder to snapshot and retrieve them.
+ std::map<int32_t /*displayId*/, bool /*inTouchMode*/> mTouchModePerDisplay GUARDED_BY(mLock);
+
class DispatcherWindowListener : public gui::WindowInfosListener {
public:
explicit DispatcherWindowListener(InputDispatcher& dispatcher) : mDispatcher(dispatcher){};
@@ -381,10 +384,10 @@
REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked(int displayId) const
REQUIRES(mLock);
- bool hasResponsiveConnectionLocked(android::gui::WindowInfoHandle& windowHandle) const
- REQUIRES(mLock);
+ bool canWindowReceiveMotionLocked(const sp<android::gui::WindowInfoHandle>& window,
+ const MotionEntry& motionEntry) const REQUIRES(mLock);
- // Gets all the input targets (with their respective input channels) from the window handles
+ // Returns all the input targets (with their respective input channels) from the window handles
// passed as argument.
std::vector<InputTarget> getInputTargetsFromWindowHandlesLocked(
const std::vector<sp<android::gui::WindowInfoHandle>>& windowHandles) const
@@ -685,9 +688,6 @@
bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
- // Per display touch mode enabled
- const bool kPerDisplayTouchModeEnabled;
-
sp<InputReporterInterface> mReporter;
};
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 44f3baf..7843923 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -136,9 +136,6 @@
/* Notifies the policy that the drag window has moved over to another window */
virtual void notifyDropWindow(const sp<IBinder>& token, float x, float y) = 0;
-
- /* If touch mode is enabled per display or global */
- virtual bool isPerDisplayTouchModeEnabled() = 0;
};
} // namespace android
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 036d57e..1bb1968 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -21,199 +21,11 @@
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/TouchVideoFrame.h>
+#include "NotifyArgs.h"
namespace android {
-class InputListenerInterface;
-
-/* Describes a configuration change event. */
-struct NotifyConfigurationChangedArgs {
- int32_t id;
- nsecs_t eventTime;
-
- inline NotifyConfigurationChangedArgs() { }
-
- NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime);
-
- bool operator==(const NotifyConfigurationChangedArgs& rhs) const = default;
-
- NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other) = default;
-};
-
-/* Describes a key event. */
-struct NotifyKeyArgs {
- int32_t id;
- nsecs_t eventTime;
-
- int32_t deviceId;
- uint32_t source;
- int32_t displayId;
- uint32_t policyFlags;
- int32_t action;
- int32_t flags;
- int32_t keyCode;
- int32_t scanCode;
- int32_t metaState;
- nsecs_t downTime;
- nsecs_t readTime;
-
- inline NotifyKeyArgs() { }
-
- NotifyKeyArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId,
- uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
- int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
- nsecs_t downTime);
-
- bool operator==(const NotifyKeyArgs& rhs) const = default;
-
- NotifyKeyArgs(const NotifyKeyArgs& other) = default;
-};
-
-/* Describes a motion event. */
-struct NotifyMotionArgs {
- int32_t id;
- nsecs_t eventTime;
-
- int32_t deviceId;
- uint32_t source;
- int32_t displayId;
- uint32_t policyFlags;
- int32_t action;
- int32_t actionButton;
- int32_t flags;
- int32_t metaState;
- int32_t buttonState;
- /**
- * Classification of the current touch gesture
- */
- MotionClassification classification;
- int32_t edgeFlags;
-
- uint32_t pointerCount;
- PointerProperties pointerProperties[MAX_POINTERS];
- PointerCoords pointerCoords[MAX_POINTERS];
- float xPrecision;
- float yPrecision;
- /**
- * Mouse cursor position when this event is reported relative to the origin of the specified
- * display. Only valid if this is a mouse event (originates from a mouse or from a trackpad in
- * gestures enabled mode.
- */
- float xCursorPosition;
- float yCursorPosition;
- nsecs_t downTime;
- nsecs_t readTime;
- std::vector<TouchVideoFrame> videoFrames;
-
- inline NotifyMotionArgs() { }
-
- NotifyMotionArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId,
- uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
- int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState,
- MotionClassification classification, int32_t edgeFlags, uint32_t pointerCount,
- const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames);
-
- NotifyMotionArgs(const NotifyMotionArgs& other);
-
- bool operator==(const NotifyMotionArgs& rhs) const;
-
- std::string dump() const;
-};
-
-/* Describes a sensor event. */
-struct NotifySensorArgs {
- int32_t id;
- nsecs_t eventTime;
-
- int32_t deviceId;
- uint32_t source;
- InputDeviceSensorType sensorType;
- InputDeviceSensorAccuracy accuracy;
- bool accuracyChanged;
- nsecs_t hwTimestamp;
- std::vector<float> values;
-
- inline NotifySensorArgs() {}
-
- NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
- InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy,
- bool accuracyChanged, nsecs_t hwTimestamp, std::vector<float> values);
-
- NotifySensorArgs(const NotifySensorArgs& other) = default;
-};
-
-/* Describes a switch event. */
-struct NotifySwitchArgs {
- int32_t id;
- nsecs_t eventTime;
-
- uint32_t policyFlags;
- uint32_t switchValues;
- uint32_t switchMask;
-
- inline NotifySwitchArgs() { }
-
- NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, uint32_t switchValues,
- uint32_t switchMask);
-
- NotifySwitchArgs(const NotifySwitchArgs& other) = default;
-
- bool operator==(const NotifySwitchArgs& rhs) const = default;
-};
-
-/* Describes a device reset event, such as when a device is added,
- * reconfigured, or removed. */
-struct NotifyDeviceResetArgs {
- int32_t id;
- nsecs_t eventTime;
-
- int32_t deviceId;
-
- inline NotifyDeviceResetArgs() { }
-
- NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId);
-
- NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) = default;
-
- bool operator==(const NotifyDeviceResetArgs& rhs) const = default;
-};
-
-/* Describes a change in the state of Pointer Capture. */
-struct NotifyPointerCaptureChangedArgs {
- // The sequence number of the Pointer Capture request, if enabled.
- int32_t id;
- nsecs_t eventTime;
-
- PointerCaptureRequest request;
-
- inline NotifyPointerCaptureChangedArgs() {}
-
- NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, const PointerCaptureRequest&);
-
- NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other) = default;
-};
-
-/* Describes a vibrator state event. */
-struct NotifyVibratorStateArgs {
- int32_t id;
- nsecs_t eventTime;
-
- int32_t deviceId;
- bool isOn;
-
- inline NotifyVibratorStateArgs() {}
-
- NotifyVibratorStateArgs(int32_t id, nsecs_t eventTIme, int32_t deviceId, bool isOn);
-
- NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other);
-};
-
-using NotifyArgs = std::variant<NotifyConfigurationChangedArgs, NotifyKeyArgs, NotifyMotionArgs,
- NotifySensorArgs, NotifySwitchArgs, NotifyDeviceResetArgs,
- NotifyPointerCaptureChangedArgs, NotifyVibratorStateArgs>;
+std::list<NotifyArgs>& operator+=(std::list<NotifyArgs>& keep, std::list<NotifyArgs>&& consume);
/*
* The interface used by the InputReader to notify the InputListener about input events.
diff --git a/services/inputflinger/include/NotifyArgs.h b/services/inputflinger/include/NotifyArgs.h
new file mode 100644
index 0000000..f28dbf3
--- /dev/null
+++ b/services/inputflinger/include/NotifyArgs.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <input/Input.h>
+#include <input/InputDevice.h>
+#include <input/TouchVideoFrame.h>
+
+namespace android {
+
+/* Describes a configuration change event. */
+struct NotifyConfigurationChangedArgs {
+ int32_t id;
+ nsecs_t eventTime;
+
+ inline NotifyConfigurationChangedArgs() {}
+
+ NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime);
+
+ bool operator==(const NotifyConfigurationChangedArgs& rhs) const = default;
+
+ NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other) = default;
+};
+
+/* Describes a key event. */
+struct NotifyKeyArgs {
+ int32_t id;
+ nsecs_t eventTime;
+
+ int32_t deviceId;
+ uint32_t source;
+ int32_t displayId;
+ uint32_t policyFlags;
+ int32_t action;
+ int32_t flags;
+ int32_t keyCode;
+ int32_t scanCode;
+ int32_t metaState;
+ nsecs_t downTime;
+ nsecs_t readTime;
+
+ inline NotifyKeyArgs() {}
+
+ NotifyKeyArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId,
+ uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
+ int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
+ nsecs_t downTime);
+
+ bool operator==(const NotifyKeyArgs& rhs) const = default;
+
+ NotifyKeyArgs(const NotifyKeyArgs& other) = default;
+};
+
+/* Describes a motion event. */
+struct NotifyMotionArgs {
+ int32_t id;
+ nsecs_t eventTime;
+
+ int32_t deviceId;
+ uint32_t source;
+ int32_t displayId;
+ uint32_t policyFlags;
+ int32_t action;
+ int32_t actionButton;
+ int32_t flags;
+ int32_t metaState;
+ int32_t buttonState;
+ /**
+ * Classification of the current touch gesture
+ */
+ MotionClassification classification;
+ int32_t edgeFlags;
+
+ uint32_t pointerCount;
+ PointerProperties pointerProperties[MAX_POINTERS];
+ PointerCoords pointerCoords[MAX_POINTERS];
+ float xPrecision;
+ float yPrecision;
+ /**
+ * Mouse cursor position when this event is reported relative to the origin of the specified
+ * display. Only valid if this is a mouse event (originates from a mouse or from a trackpad in
+ * gestures enabled mode.
+ */
+ float xCursorPosition;
+ float yCursorPosition;
+ nsecs_t downTime;
+ nsecs_t readTime;
+ std::vector<TouchVideoFrame> videoFrames;
+
+ inline NotifyMotionArgs() {}
+
+ NotifyMotionArgs(int32_t id, nsecs_t eventTime, nsecs_t readTime, int32_t deviceId,
+ uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
+ int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState,
+ MotionClassification classification, int32_t edgeFlags, uint32_t pointerCount,
+ const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
+ float xPrecision, float yPrecision, float xCursorPosition,
+ float yCursorPosition, nsecs_t downTime,
+ const std::vector<TouchVideoFrame>& videoFrames);
+
+ NotifyMotionArgs(const NotifyMotionArgs& other);
+
+ bool operator==(const NotifyMotionArgs& rhs) const;
+
+ std::string dump() const;
+};
+
+/* Describes a sensor event. */
+struct NotifySensorArgs {
+ int32_t id;
+ nsecs_t eventTime;
+
+ int32_t deviceId;
+ uint32_t source;
+ InputDeviceSensorType sensorType;
+ InputDeviceSensorAccuracy accuracy;
+ bool accuracyChanged;
+ nsecs_t hwTimestamp;
+ std::vector<float> values;
+
+ inline NotifySensorArgs() {}
+
+ NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+ InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy,
+ bool accuracyChanged, nsecs_t hwTimestamp, std::vector<float> values);
+
+ NotifySensorArgs(const NotifySensorArgs& other) = default;
+};
+
+/* Describes a switch event. */
+struct NotifySwitchArgs {
+ int32_t id;
+ nsecs_t eventTime;
+
+ uint32_t policyFlags;
+ uint32_t switchValues;
+ uint32_t switchMask;
+
+ inline NotifySwitchArgs() {}
+
+ NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, uint32_t switchValues,
+ uint32_t switchMask);
+
+ NotifySwitchArgs(const NotifySwitchArgs& other) = default;
+
+ bool operator==(const NotifySwitchArgs& rhs) const = default;
+};
+
+/* Describes a device reset event, such as when a device is added,
+ * reconfigured, or removed. */
+struct NotifyDeviceResetArgs {
+ int32_t id;
+ nsecs_t eventTime;
+
+ int32_t deviceId;
+
+ inline NotifyDeviceResetArgs() {}
+
+ NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId);
+
+ NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) = default;
+
+ bool operator==(const NotifyDeviceResetArgs& rhs) const = default;
+};
+
+/* Describes a change in the state of Pointer Capture. */
+struct NotifyPointerCaptureChangedArgs {
+ // The sequence number of the Pointer Capture request, if enabled.
+ int32_t id;
+ nsecs_t eventTime;
+
+ PointerCaptureRequest request;
+
+ inline NotifyPointerCaptureChangedArgs() {}
+
+ NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, const PointerCaptureRequest&);
+
+ NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other) = default;
+};
+
+/* Describes a vibrator state event. */
+struct NotifyVibratorStateArgs {
+ int32_t id;
+ nsecs_t eventTime;
+
+ int32_t deviceId;
+ bool isOn;
+
+ inline NotifyVibratorStateArgs() {}
+
+ NotifyVibratorStateArgs(int32_t id, nsecs_t eventTIme, int32_t deviceId, bool isOn);
+
+ NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other) = default;
+};
+
+using NotifyArgs = std::variant<NotifyConfigurationChangedArgs, NotifyKeyArgs, NotifyMotionArgs,
+ NotifySensorArgs, NotifySwitchArgs, NotifyDeviceResetArgs,
+ NotifyPointerCaptureChangedArgs, NotifyVibratorStateArgs>;
+
+const char* toString(const NotifyArgs& args);
+
+} // namespace android
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 01146a3..0f87201 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -69,12 +69,12 @@
"libinput",
"liblog",
"libstatslog",
- "libui",
"libutils",
"libPlatformProperties",
],
static_libs: [
"libc++fs",
+ "libui-types",
],
header_libs: [
"libbatteryservice_headers",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 5c24244..ca7e426 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1418,17 +1418,28 @@
}
const auto& path = *sysfsRootPathOpt;
- for (const auto& [id, dev] : mDevices) {
- if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == path) {
- return dev->associatedDevice;
- }
- }
- return std::make_shared<AssociatedDevice>(
+ std::shared_ptr<const AssociatedDevice> associatedDevice = std::make_shared<AssociatedDevice>(
AssociatedDevice{.sysfsRootPath = path,
.countryCode = readCountryCodeLocked(path),
.batteryInfos = readBatteryConfiguration(path),
.lightInfos = readLightsConfiguration(path)});
+
+ bool associatedDeviceChanged = false;
+ for (const auto& [id, dev] : mDevices) {
+ if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == path) {
+ if (*associatedDevice != *dev->associatedDevice) {
+ associatedDeviceChanged = true;
+ dev->associatedDevice = associatedDevice;
+ }
+ associatedDevice = dev->associatedDevice;
+ }
+ }
+ ALOGI_IF(associatedDeviceChanged,
+ "The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s",
+ path.c_str(), associatedDevice->dump().c_str());
+
+ return associatedDevice;
}
void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
@@ -1638,11 +1649,9 @@
std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) {
std::scoped_lock _l(mLock);
- constexpr size_t bufferSize = EVENT_BUFFER_SIZE;
- struct input_event readBuffer[bufferSize];
+ std::array<input_event, EVENT_BUFFER_SIZE> readBuffer;
std::vector<RawEvent> events;
- size_t capacity = bufferSize;
bool awoken = false;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -1672,7 +1681,7 @@
});
it = mClosingDevices.erase(it);
mNeedToSendFinishedDeviceScan = true;
- if (events.size() == capacity) {
+ if (events.size() == EVENT_BUFFER_SIZE) {
break;
}
}
@@ -1710,7 +1719,7 @@
ALOGW("Device id %d exists, replaced.", device->id);
}
mNeedToSendFinishedDeviceScan = true;
- if (events.size() == capacity) {
+ if (events.size() == EVENT_BUFFER_SIZE) {
break;
}
}
@@ -1721,7 +1730,7 @@
.when = now,
.type = FINISHED_DEVICE_SCAN,
});
- if (events.size() == capacity) {
+ if (events.size() == EVENT_BUFFER_SIZE) {
break;
}
}
@@ -1785,12 +1794,13 @@
// This must be an input event
if (eventItem.events & EPOLLIN) {
int32_t readSize =
- read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
+ read(device->fd, readBuffer.data(),
+ sizeof(decltype(readBuffer)::value_type) * readBuffer.size());
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
- " bufferSize: %zu capacity: %zu errno: %d)\n",
- device->fd, readSize, bufferSize, capacity, errno);
+ " capacity: %zu errno: %d)\n",
+ device->fd, readSize, readBuffer.size(), errno);
deviceChanged = true;
closeDeviceLocked(*device);
} else if (readSize < 0) {
@@ -1814,7 +1824,7 @@
.value = iev.value,
});
}
- if (events.size() >= capacity) {
+ if (events.size() >= EVENT_BUFFER_SIZE) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1;
@@ -2651,4 +2661,9 @@
std::unique_lock<std::mutex> lock(mLock);
}
+std::string EventHub::AssociatedDevice::dump() const {
+ return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(),
+ batteryInfos.size(), lightInfos.size());
+}
+
} // namespace android
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 44a005e..5291776 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -65,7 +65,8 @@
return enabled;
}
-void InputDevice::setEnabled(bool enabled, nsecs_t when) {
+std::list<NotifyArgs> InputDevice::setEnabled(bool enabled, nsecs_t when) {
+ std::list<NotifyArgs> out;
if (enabled && mAssociatedDisplayPort && !mAssociatedViewport) {
ALOGW("Cannot enable input device %s because it is associated with port %" PRIu8 ", "
"but the corresponding viewport is not found",
@@ -74,7 +75,7 @@
}
if (isEnabled() == enabled) {
- return;
+ return out;
}
// When resetting some devices, the driver needs to be queried to ensure that a proper reset is
@@ -82,13 +83,14 @@
// but before disabling the device. See MultiTouchMotionAccumulator::reset for more information.
if (enabled) {
for_each_subdevice([](auto& context) { context.enableDevice(); });
- reset(when);
+ out += reset(when);
} else {
- reset(when);
+ out += reset(when);
for_each_subdevice([](auto& context) { context.disableDevice(); });
}
// Must change generation to flag this device as changed
bumpGeneration();
+ return out;
}
void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) {
@@ -234,11 +236,16 @@
}
void InputDevice::removeEventHubDevice(int32_t eventHubId) {
+ if (mController != nullptr && mController->getEventHubId() == eventHubId) {
+ // Delete mController, since the corresponding eventhub device is going away
+ mController = nullptr;
+ }
mDevices.erase(eventHubId);
}
-void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
+std::list<NotifyArgs> InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) {
+ std::list<NotifyArgs> out;
mSources = 0;
mClasses = ftl::Flags<InputDeviceClass>(0);
mControllerNumber = 0;
@@ -309,7 +316,7 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) {
auto it = config->disabledDevices.find(mId);
bool enabled = it == config->disabledDevices.end();
- setEnabled(enabled, when);
+ out += setEnabled(enabled, when);
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
@@ -362,37 +369,42 @@
// For first-time configuration, only allow device to be disabled after mappers have
// finished configuring. This is because we need to read some of the properties from
// the device's open fd.
- setEnabled(enabled, when);
+ out += setEnabled(enabled, when);
}
}
- for_each_mapper([this, when, config, changes](InputMapper& mapper) {
- mapper.configure(when, config, changes);
+ for_each_mapper([this, when, &config, changes, &out](InputMapper& mapper) {
+ out += mapper.configure(when, config, changes);
mSources |= mapper.getSources();
});
// If a device is just plugged but it might be disabled, we need to update some info like
// axis range of touch from each InputMapper first, then disable it.
if (!changes) {
- setEnabled(config->disabledDevices.find(mId) == config->disabledDevices.end(), when);
+ out += setEnabled(config->disabledDevices.find(mId) == config->disabledDevices.end(),
+ when);
}
}
+ return out;
}
-void InputDevice::reset(nsecs_t when) {
- for_each_mapper([when](InputMapper& mapper) { mapper.reset(when); });
+std::list<NotifyArgs> InputDevice::reset(nsecs_t when) {
+ std::list<NotifyArgs> out;
+ for_each_mapper([&](InputMapper& mapper) { out += mapper.reset(when); });
mContext->updateGlobalMetaState();
- notifyReset(when);
+ out.push_back(notifyReset(when));
+ return out;
}
-void InputDevice::process(const RawEvent* rawEvents, size_t count) {
+std::list<NotifyArgs> InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
+ std::list<NotifyArgs> out;
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
if (DEBUG_RAW_EVENTS) {
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
@@ -414,22 +426,27 @@
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
- reset(rawEvent->when);
+ out += reset(rawEvent->when);
} else {
- for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
- mapper.process(rawEvent);
+ for_each_mapper_in_subdevice(rawEvent->deviceId, [&](InputMapper& mapper) {
+ out += mapper.process(rawEvent);
});
}
--count;
}
+ return out;
}
-void InputDevice::timeoutExpired(nsecs_t when) {
- for_each_mapper([when](InputMapper& mapper) { mapper.timeoutExpired(when); });
+std::list<NotifyArgs> InputDevice::timeoutExpired(nsecs_t when) {
+ std::list<NotifyArgs> out;
+ for_each_mapper([&](InputMapper& mapper) { out += mapper.timeoutExpired(when); });
+ return out;
}
-void InputDevice::updateExternalStylusState(const StylusState& state) {
- for_each_mapper([state](InputMapper& mapper) { mapper.updateExternalStylusState(state); });
+std::list<NotifyArgs> InputDevice::updateExternalStylusState(const StylusState& state) {
+ std::list<NotifyArgs> out;
+ for_each_mapper([&](InputMapper& mapper) { out += mapper.updateExternalStylusState(state); });
+ return out;
}
InputDeviceInfo InputDevice::getDeviceInfo() {
@@ -507,14 +524,17 @@
return *result;
}
-void InputDevice::vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) {
- for_each_mapper([sequence, repeat, token](InputMapper& mapper) {
- mapper.vibrate(sequence, repeat, token);
- });
+std::list<NotifyArgs> InputDevice::vibrate(const VibrationSequence& sequence, ssize_t repeat,
+ int32_t token) {
+ std::list<NotifyArgs> out;
+ for_each_mapper([&](InputMapper& mapper) { out += mapper.vibrate(sequence, repeat, token); });
+ return out;
}
-void InputDevice::cancelVibrate(int32_t token) {
- for_each_mapper([token](InputMapper& mapper) { mapper.cancelVibrate(token); });
+std::list<NotifyArgs> InputDevice::cancelVibrate(int32_t token) {
+ std::list<NotifyArgs> out;
+ for_each_mapper([&](InputMapper& mapper) { out += mapper.cancelVibrate(token); });
+ return out;
}
bool InputDevice::isVibrating() {
@@ -557,8 +577,10 @@
for_each_mapper([sensorType](InputMapper& mapper) { mapper.flushSensor(sensorType); });
}
-void InputDevice::cancelTouch(nsecs_t when, nsecs_t readTime) {
- for_each_mapper([when, readTime](InputMapper& mapper) { mapper.cancelTouch(when, readTime); });
+std::list<NotifyArgs> InputDevice::cancelTouch(nsecs_t when, nsecs_t readTime) {
+ std::list<NotifyArgs> out;
+ for_each_mapper([&](InputMapper& mapper) { out += mapper.cancelTouch(when, readTime); });
+ return out;
}
bool InputDevice::setLightColor(int32_t lightId, int32_t color) {
@@ -597,9 +619,8 @@
mGeneration = mContext->bumpGeneration();
}
-void InputDevice::notifyReset(nsecs_t when) {
- NotifyDeviceResetArgs args(mContext->getNextId(), when, mId);
- mContext->getListener().notifyDeviceReset(&args);
+NotifyDeviceResetArgs InputDevice::notifyReset(nsecs_t when) {
+ return NotifyDeviceResetArgs(mContext->getNextId(), when, mId);
}
std::optional<int32_t> InputDevice::getAssociatedDisplayId() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 8650876..428e999 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -127,7 +127,7 @@
mReaderIsAliveCondition.notify_all();
if (!events.empty()) {
- processEventsLocked(events.data(), events.size());
+ notifyAll(processEventsLocked(events.data(), events.size()));
}
if (mNextTimeout != LLONG_MAX) {
@@ -137,7 +137,7 @@
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
}
mNextTimeout = LLONG_MAX;
- timeoutExpiredLocked(now);
+ notifyAll(timeoutExpiredLocked(now));
}
}
@@ -162,7 +162,8 @@
mQueuedListener.flush();
}
-void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
+std::list<NotifyArgs> InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
+ std::list<NotifyArgs> out;
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
@@ -178,7 +179,7 @@
if (DEBUG_RAW_EVENTS) {
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
}
- processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
+ out += processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
@@ -198,6 +199,7 @@
count -= batchSize;
rawEvent += batchSize;
}
+ return out;
}
void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
@@ -208,8 +210,9 @@
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
- device->configure(when, &mConfig, 0);
- device->reset(when);
+
+ notifyAll(device->configure(when, &mConfig, 0));
+ notifyAll(device->reset(when));
if (device->isIgnored()) {
ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s' "
@@ -282,10 +285,12 @@
notifyExternalStylusPresenceChangedLocked();
}
+ std::list<NotifyArgs> resetEvents;
if (device->hasEventHubDevices()) {
- device->configure(when, &mConfig, 0);
+ resetEvents += device->configure(when, &mConfig, 0);
}
- device->reset(when);
+ resetEvents += device->reset(when);
+ notifyAll(std::move(resetEvents));
}
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
@@ -308,21 +313,22 @@
return device;
}
-void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
- size_t count) {
+std::list<NotifyArgs> InputReader::processEventsForDeviceLocked(int32_t eventHubId,
+ const RawEvent* rawEvents,
+ size_t count) {
auto deviceIt = mDevices.find(eventHubId);
if (deviceIt == mDevices.end()) {
ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
- return;
+ return {};
}
std::shared_ptr<InputDevice>& device = deviceIt->second;
if (device->isIgnored()) {
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
- return;
+ return {};
}
- device->process(rawEvents, count);
+ return device->process(rawEvents, count);
}
InputDevice* InputReader::findInputDeviceLocked(int32_t deviceId) const {
@@ -336,13 +342,15 @@
return nullptr;
}
-void InputReader::timeoutExpiredLocked(nsecs_t when) {
+std::list<NotifyArgs> InputReader::timeoutExpiredLocked(nsecs_t when) {
+ std::list<NotifyArgs> out;
for (auto& devicePair : mDevices) {
std::shared_ptr<InputDevice>& device = devicePair.second;
if (!device->isIgnored()) {
- device->timeoutExpired(when);
+ out += device->timeoutExpired(when);
}
}
+ return out;
}
int32_t InputReader::nextInputDeviceIdLocked() {
@@ -377,7 +385,7 @@
} else {
for (auto& devicePair : mDevices) {
std::shared_ptr<InputDevice>& device = devicePair.second;
- device->configure(now, &mConfig, changes);
+ notifyAll(device->configure(now, &mConfig, changes));
}
}
@@ -394,6 +402,12 @@
}
}
+void InputReader::notifyAll(std::list<NotifyArgs>&& argsList) {
+ for (const NotifyArgs& args : argsList) {
+ mQueuedListener.notify(args);
+ }
+}
+
void InputReader::updateGlobalMetaStateLocked() {
mGlobalMetaState = 0;
@@ -432,11 +446,13 @@
}
}
-void InputReader::dispatchExternalStylusStateLocked(const StylusState& state) {
+std::list<NotifyArgs> InputReader::dispatchExternalStylusStateLocked(const StylusState& state) {
+ std::list<NotifyArgs> out;
for (auto& devicePair : mDevices) {
std::shared_ptr<InputDevice>& device = devicePair.second;
- device->updateExternalStylusState(state);
+ out += device->updateExternalStylusState(state);
}
+ return out;
}
void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) {
@@ -642,7 +658,7 @@
InputDevice* device = findInputDeviceLocked(deviceId);
if (device) {
- device->vibrate(sequence, repeat, token);
+ notifyAll(device->vibrate(sequence, repeat, token));
}
}
@@ -651,7 +667,7 @@
InputDevice* device = findInputDeviceLocked(deviceId);
if (device) {
- device->cancelVibrate(token);
+ notifyAll(device->cancelVibrate(token));
}
}
@@ -1015,18 +1031,15 @@
mReader->getExternalStylusDevicesLocked(outDevices);
}
-void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) {
- mReader->dispatchExternalStylusStateLocked(state);
+std::list<NotifyArgs> InputReader::ContextImpl::dispatchExternalStylusState(
+ const StylusState& state) {
+ return mReader->dispatchExternalStylusStateLocked(state);
}
InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
return mReader->mPolicy.get();
}
-InputListenerInterface& InputReader::ContextImpl::getListener() {
- return mReader->mQueuedListener;
-}
-
EventHubInterface* InputReader::ContextImpl::getEventHub() {
return mReader->mEventHub.get();
}
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 2eeb3f4..6933ec7 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -195,6 +195,9 @@
ftl::Flags<InputLightClass> flags;
std::array<int32_t, COLOR_NUM> rgbIndex;
std::filesystem::path path;
+
+ bool operator==(const RawLightInfo&) const = default;
+ bool operator!=(const RawLightInfo&) const = default;
};
/* Describes a raw battery. */
@@ -203,6 +206,9 @@
std::string name;
ftl::Flags<InputBatteryClass> flags;
std::filesystem::path path;
+
+ bool operator==(const RawBatteryInfo&) const = default;
+ bool operator!=(const RawBatteryInfo&) const = default;
};
/*
@@ -551,6 +557,10 @@
hardware::input::InputDeviceCountryCode countryCode;
std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> batteryInfos;
std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos;
+
+ bool operator==(const AssociatedDevice&) const = default;
+ bool operator!=(const AssociatedDevice&) const = default;
+ std::string dump() const;
};
struct Device {
@@ -584,7 +594,7 @@
// A shared_ptr of a device associated with the input device.
// The input devices that have the same sysfs path have the same associated device.
- const std::shared_ptr<const AssociatedDevice> associatedDevice;
+ std::shared_ptr<const AssociatedDevice> associatedDevice;
int32_t controllerNumber;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 4ae9ae9..afb1bed 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -29,6 +29,7 @@
#include "EventHub.h"
#include "InputReaderBase.h"
#include "InputReaderContext.h"
+#include "NotifyArgs.h"
namespace android {
@@ -69,16 +70,18 @@
inline bool isIgnored() { return !getMapperCount(); }
bool isEnabled();
- void setEnabled(bool enabled, nsecs_t when);
+ [[nodiscard]] std::list<NotifyArgs> setEnabled(bool enabled, nsecs_t when);
void dump(std::string& dump, const std::string& eventHubDevStr);
void addEventHubDevice(int32_t eventHubId, bool populateMappers = true);
void removeEventHubDevice(int32_t eventHubId);
- void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
- void reset(nsecs_t when);
- void process(const RawEvent* rawEvents, size_t count);
- void timeoutExpired(nsecs_t when);
- void updateExternalStylusState(const StylusState& state);
+ [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes);
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when);
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvents, size_t count);
+ [[nodiscard]] std::list<NotifyArgs> timeoutExpired(nsecs_t when);
+ [[nodiscard]] std::list<NotifyArgs> updateExternalStylusState(const StylusState& state);
InputDeviceInfo getDeviceInfo();
int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
@@ -87,11 +90,12 @@
int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const;
bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
uint8_t* outFlags);
- void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token);
- void cancelVibrate(int32_t token);
+ [[nodiscard]] std::list<NotifyArgs> vibrate(const VibrationSequence& sequence, ssize_t repeat,
+ int32_t token);
+ [[nodiscard]] std::list<NotifyArgs> cancelVibrate(int32_t token);
bool isVibrating();
std::vector<int32_t> getVibratorIds();
- void cancelTouch(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] std::list<NotifyArgs> cancelTouch(nsecs_t when, nsecs_t readTime);
bool enableSensor(InputDeviceSensorType sensorType, std::chrono::microseconds samplingPeriod,
std::chrono::microseconds maxBatchReportLatency);
void disableSensor(InputDeviceSensorType sensorType);
@@ -109,7 +113,7 @@
void bumpGeneration();
- void notifyReset(nsecs_t when);
+ [[nodiscard]] NotifyDeviceResetArgs notifyReset(nsecs_t when);
inline const PropertyMap& getConfiguration() { return mConfiguration; }
inline EventHubInterface* getEventHub() { return mContext->getEventHub(); }
@@ -395,7 +399,9 @@
inline std::optional<DisplayViewport> getAssociatedViewport() const {
return mDevice.getAssociatedViewport();
}
- inline void cancelTouch(nsecs_t when, nsecs_t readTime) { mDevice.cancelTouch(when, readTime); }
+ [[nodiscard]] inline std::list<NotifyArgs> cancelTouch(nsecs_t when, nsecs_t readTime) {
+ return mDevice.cancelTouch(when, readTime);
+ }
inline void bumpGeneration() { mDevice.bumpGeneration(); }
inline const PropertyMap& getConfiguration() { return mDevice.getConfiguration(); }
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 012d43f..de268cf 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -142,10 +142,9 @@
int32_t bumpGeneration() NO_THREAD_SAFETY_ANALYSIS override;
void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices)
REQUIRES(mReader->mLock) override;
- void dispatchExternalStylusState(const StylusState& outState)
+ [[nodiscard]] std::list<NotifyArgs> dispatchExternalStylusState(const StylusState& outState)
REQUIRES(mReader->mLock) override;
InputReaderPolicyInterface* getPolicy() REQUIRES(mReader->mLock) override;
- InputListenerInterface& getListener() REQUIRES(mReader->mLock) override;
EventHubInterface* getEventHub() REQUIRES(mReader->mLock) override;
int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override;
void updateLedMetaState(int32_t metaState) REQUIRES(mReader->mLock) override;
@@ -181,13 +180,15 @@
mDeviceToEventHubIdsMap GUARDED_BY(mLock);
// low-level input event decoding and device management
- void processEventsLocked(const RawEvent* rawEvents, size_t count) REQUIRES(mLock);
+ [[nodiscard]] std::list<NotifyArgs> processEventsLocked(const RawEvent* rawEvents, size_t count)
+ REQUIRES(mLock);
void addDeviceLocked(nsecs_t when, int32_t eventHubId) REQUIRES(mLock);
void removeDeviceLocked(nsecs_t when, int32_t eventHubId) REQUIRES(mLock);
- void processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count)
- REQUIRES(mLock);
- void timeoutExpiredLocked(nsecs_t when) REQUIRES(mLock);
+ [[nodiscard]] std::list<NotifyArgs> processEventsForDeviceLocked(int32_t eventHubId,
+ const RawEvent* rawEvents,
+ size_t count) REQUIRES(mLock);
+ [[nodiscard]] std::list<NotifyArgs> timeoutExpiredLocked(nsecs_t when) REQUIRES(mLock);
void handleConfigurationChangedLocked(nsecs_t when) REQUIRES(mLock);
@@ -201,7 +202,8 @@
void notifyExternalStylusPresenceChangedLocked() REQUIRES(mLock);
void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) REQUIRES(mLock);
- void dispatchExternalStylusStateLocked(const StylusState& state) REQUIRES(mLock);
+ [[nodiscard]] std::list<NotifyArgs> dispatchExternalStylusStateLocked(const StylusState& state)
+ REQUIRES(mLock);
// The PointerController that is shared among all the input devices that need it.
std::weak_ptr<PointerControllerInterface> mPointerController;
@@ -228,6 +230,8 @@
uint32_t mConfigurationChangesToRefresh GUARDED_BY(mLock);
void refreshConfigurationLocked(uint32_t changes) REQUIRES(mLock);
+ void notifyAll(std::list<NotifyArgs>&& argsList);
+
PointerCaptureRequest mCurrentPointerCaptureRequest GUARDED_BY(mLock);
// state queries
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index f2f156c..0beace1 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -17,6 +17,7 @@
#pragma once
#include <input/InputDevice.h>
+#include "NotifyArgs.h"
#include <vector>
@@ -51,10 +52,10 @@
virtual int32_t bumpGeneration() = 0;
virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) = 0;
- virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
+ [[nodiscard]] virtual std::list<NotifyArgs> dispatchExternalStylusState(
+ const StylusState& outState) = 0;
virtual InputReaderPolicyInterface* getPolicy() = 0;
- virtual InputListenerInterface& getListener() = 0;
virtual EventHubInterface* getEventHub() = 0;
virtual int32_t getNextId() = 0;
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index d6d324b..c691ca9 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -126,9 +126,10 @@
dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
}
-void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
- InputMapper::configure(when, config, changes);
+std::list<NotifyArgs> CursorInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) {
+ std::list<NotifyArgs> out = InputMapper::configure(when, config, changes);
if (!changes) { // first time only
mCursorScrollAccumulator.configure(getDeviceContext());
@@ -187,8 +188,7 @@
}
bumpGeneration();
if (changes) {
- NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
- getListener().notifyDeviceReset(&args);
+ out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
}
}
@@ -241,6 +241,7 @@
bumpGeneration();
}
+ return out;
}
void CursorInputMapper::configureParameters() {
@@ -272,7 +273,7 @@
dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
}
-void CursorInputMapper::reset(nsecs_t when) {
+std::list<NotifyArgs> CursorInputMapper::reset(nsecs_t when) {
mButtonState = 0;
mDownTime = 0;
@@ -284,23 +285,26 @@
mCursorMotionAccumulator.reset(getDeviceContext());
mCursorScrollAccumulator.reset(getDeviceContext());
- InputMapper::reset(when);
+ return InputMapper::reset(when);
}
-void CursorInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> CursorInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out;
mCursorButtonAccumulator.process(rawEvent);
mCursorMotionAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- sync(rawEvent->when, rawEvent->readTime);
+ out += sync(rawEvent->when, rawEvent->readTime);
}
+ return out;
}
-void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+std::list<NotifyArgs> CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+ std::list<NotifyArgs> out;
if (!mDisplayId) {
// Ignore events when there is no target display configured.
- return;
+ return out;
}
int32_t lastButtonState = mButtonState;
@@ -391,8 +395,9 @@
}
// Synthesize key down from buttons if needed.
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
- mSource, *mDisplayId, policyFlags, lastButtonState, currentButtonState);
+ out += synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
+ mSource, *mDisplayId, policyFlags, lastButtonState,
+ currentButtonState);
// Send motion event.
if (downChanged || moved || scrolled || buttonsChanged) {
@@ -412,40 +417,38 @@
while (!released.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
buttonState &= ~actionButton;
- NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, readTime,
- getDeviceId(), mSource, *mDisplayId, policyFlags,
- AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
- metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision,
- xCursorPosition, yCursorPosition, downTime,
- /* videoFrames */ {});
- getListener().notifyMotion(&releaseArgs);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime,
+ getDeviceId(), mSource, *mDisplayId, policyFlags,
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+ metaState, buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {}));
}
}
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- *mDisplayId, policyFlags, motionEventAction, 0, 0, metaState,
- currentButtonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
- mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
- /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, *mDisplayId, policyFlags, motionEventAction, 0, 0,
+ metaState, currentButtonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+ yCursorPosition, downTime,
+ /* videoFrames */ {}));
if (buttonsPressed) {
BitSet32 pressed(buttonsPressed);
while (!pressed.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
buttonState |= actionButton;
- NotifyMotionArgs pressArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, *mDisplayId, policyFlags,
- AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
- metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision,
- xCursorPosition, yCursorPosition, downTime,
- /* videoFrames */ {});
- getListener().notifyMotion(&pressArgs);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime,
+ getDeviceId(), mSource, *mDisplayId, policyFlags,
+ AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
+ metaState, buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {}));
}
}
@@ -453,14 +456,14 @@
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
- NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, *mDisplayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
- currentButtonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
- yCursorPosition, downTime, /* videoFrames */ {});
- getListener().notifyMotion(&hoverArgs);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, *mDisplayId, policyFlags,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ currentButtonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {}));
}
// Send scroll events.
@@ -468,23 +471,25 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, *mDisplayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
- currentButtonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
- yCursorPosition, downTime, /* videoFrames */ {});
- getListener().notifyMotion(&scrollArgs);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, *mDisplayId, policyFlags,
+ AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+ currentButtonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {}));
}
}
// Synthesize key up from buttons if needed.
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,
- *mDisplayId, policyFlags, lastButtonState, currentButtonState);
+ out += synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(),
+ mSource, *mDisplayId, policyFlags, lastButtonState,
+ currentButtonState);
mCursorMotionAccumulator.finishSync();
mCursorScrollAccumulator.finishSync();
+ return out;
}
int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index a0229a7..6a4275e 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -58,10 +58,11 @@
virtual uint32_t getSources() const override;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
virtual void dump(std::string& dump) override;
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) override;
- virtual void reset(nsecs_t when) override;
- virtual void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
@@ -124,7 +125,7 @@
void configureParameters();
void dumpParameters(std::string& dump);
- void sync(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
index 6b5d37f..0404c9a 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
@@ -44,28 +44,32 @@
dumpStylusState(dump, mStylusState);
}
-void ExternalStylusInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
+std::list<NotifyArgs> ExternalStylusInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) {
getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis);
mTouchButtonAccumulator.configure(getDeviceContext());
+ return {};
}
-void ExternalStylusInputMapper::reset(nsecs_t when) {
+std::list<NotifyArgs> ExternalStylusInputMapper::reset(nsecs_t when) {
mSingleTouchMotionAccumulator.reset(getDeviceContext());
mTouchButtonAccumulator.reset(getDeviceContext());
- InputMapper::reset(when);
+ return InputMapper::reset(when);
}
-void ExternalStylusInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> ExternalStylusInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out;
mSingleTouchMotionAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- sync(rawEvent->when);
+ out += sync(rawEvent->when);
}
+ return out;
}
-void ExternalStylusInputMapper::sync(nsecs_t when) {
+std::list<NotifyArgs> ExternalStylusInputMapper::sync(nsecs_t when) {
mStylusState.clear();
mStylusState.when = when;
@@ -86,7 +90,7 @@
mStylusState.buttons = mTouchButtonAccumulator.getButtonState();
- getContext()->dispatchExternalStylusState(mStylusState);
+ return getContext()->dispatchExternalStylusState(mStylusState);
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
index 03d9909..b6c9055 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
@@ -29,13 +29,14 @@
explicit ExternalStylusInputMapper(InputDeviceContext& deviceContext);
virtual ~ExternalStylusInputMapper() = default;
- virtual uint32_t getSources() const override;
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
- virtual void dump(std::string& dump) override;
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) override;
- virtual void reset(nsecs_t when) override;
- virtual void process(const RawEvent* rawEvent) override;
+ uint32_t getSources() const override;
+ void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void dump(std::string& dump) override;
+ [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
private:
SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
@@ -44,7 +45,7 @@
StylusState mStylusState;
- void sync(nsecs_t when);
+ [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index 75cebf3..844afe0 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -32,12 +32,18 @@
void InputMapper::dump(std::string& dump) {}
-void InputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {}
+std::list<NotifyArgs> InputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) {
+ return {};
+}
-void InputMapper::reset(nsecs_t when) {}
+std::list<NotifyArgs> InputMapper::reset(nsecs_t when) {
+ return {};
+}
-void InputMapper::timeoutExpired(nsecs_t when) {}
+std::list<NotifyArgs> InputMapper::timeoutExpired(nsecs_t when) {
+ return {};
+}
int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
return AKEY_STATE_UNKNOWN;
@@ -60,9 +66,14 @@
return false;
}
-void InputMapper::vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) {}
+std::list<NotifyArgs> InputMapper::vibrate(const VibrationSequence& sequence, ssize_t repeat,
+ int32_t token) {
+ return {};
+}
-void InputMapper::cancelVibrate(int32_t token) {}
+std::list<NotifyArgs> InputMapper::cancelVibrate(int32_t token) {
+ return {};
+}
bool InputMapper::isVibrating() {
return false;
@@ -72,7 +83,9 @@
return {};
}
-void InputMapper::cancelTouch(nsecs_t when, nsecs_t readTime) {}
+std::list<NotifyArgs> InputMapper::cancelTouch(nsecs_t when, nsecs_t readTime) {
+ return {};
+}
bool InputMapper::enableSensor(InputDeviceSensorType sensorType,
std::chrono::microseconds samplingPeriod,
@@ -92,7 +105,9 @@
return false;
}
-void InputMapper::updateExternalStylusState(const StylusState& state) {}
+std::list<NotifyArgs> InputMapper::updateExternalStylusState(const StylusState& state) {
+ return {};
+}
status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) {
return getDeviceContext().getAbsoluteAxisInfo(axis, axisInfo);
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 5567cac..104305b 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -20,6 +20,7 @@
#include "InputDevice.h"
#include "InputListener.h"
#include "InputReaderContext.h"
+#include "NotifyArgs.h"
#include "StylusState.h"
#include "VibrationElement.h"
@@ -48,15 +49,16 @@
inline const std::string getDeviceName() const { return mDeviceContext.getName(); }
inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); }
- inline InputListenerInterface& getListener() { return getContext()->getListener(); }
virtual uint32_t getSources() const = 0;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
virtual void dump(std::string& dump);
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent) = 0;
- virtual void timeoutExpired(nsecs_t when);
+ [[nodiscard]] virtual std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes);
+ [[nodiscard]] virtual std::list<NotifyArgs> reset(nsecs_t when);
+ [[nodiscard]] virtual std::list<NotifyArgs> process(const RawEvent* rawEvent) = 0;
+ [[nodiscard]] virtual std::list<NotifyArgs> timeoutExpired(nsecs_t when);
virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
@@ -65,11 +67,12 @@
virtual bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
uint8_t* outFlags);
- virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token);
- virtual void cancelVibrate(int32_t token);
+ [[nodiscard]] virtual std::list<NotifyArgs> vibrate(const VibrationSequence& sequence,
+ ssize_t repeat, int32_t token);
+ [[nodiscard]] virtual std::list<NotifyArgs> cancelVibrate(int32_t token);
virtual bool isVibrating();
virtual std::vector<int32_t> getVibratorIds();
- virtual void cancelTouch(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] virtual std::list<NotifyArgs> cancelTouch(nsecs_t when, nsecs_t readTime);
virtual bool enableSensor(InputDeviceSensorType sensorType,
std::chrono::microseconds samplingPeriod,
std::chrono::microseconds maxBatchReportLatency);
@@ -91,7 +94,7 @@
*/
virtual bool updateMetaState(int32_t keyCode);
- virtual void updateExternalStylusState(const StylusState& state);
+ [[nodiscard]] virtual std::list<NotifyArgs> updateExternalStylusState(const StylusState& state);
virtual std::optional<int32_t> getAssociatedDisplayId() { return std::nullopt; }
virtual void updateLedState(bool reset) {}
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 7d30d0c..929bf18 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -103,9 +103,10 @@
}
}
-void JoystickInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
- InputMapper::configure(when, config, changes);
+std::list<NotifyArgs> JoystickInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) {
+ std::list<NotifyArgs> out = InputMapper::configure(when, config, changes);
if (!changes) { // first time only
// Collect all axes.
@@ -145,12 +146,12 @@
for (auto it = mAxes.begin(); it != mAxes.end(); /*increment it inside loop*/) {
Axis& axis = it->second;
if (axis.axisInfo.axis < 0) {
- while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 &&
+ while (nextGenericAxisId <= AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE &&
haveAxis(nextGenericAxisId)) {
nextGenericAxisId += 1;
}
- if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) {
+ if (nextGenericAxisId <= AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE) {
axis.axisInfo.axis = nextGenericAxisId;
nextGenericAxisId += 1;
} else {
@@ -164,6 +165,7 @@
it++;
}
}
+ return out;
}
JoystickInputMapper::Axis JoystickInputMapper::createAxis(const AxisInfo& axisInfo,
@@ -246,17 +248,18 @@
}
}
-void JoystickInputMapper::reset(nsecs_t when) {
+std::list<NotifyArgs> JoystickInputMapper::reset(nsecs_t when) {
// Recenter all axes.
for (std::pair<const int32_t, Axis>& pair : mAxes) {
Axis& axis = pair.second;
axis.resetValue();
}
- InputMapper::reset(when);
+ return InputMapper::reset(when);
}
-void JoystickInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> JoystickInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out;
switch (rawEvent->type) {
case EV_ABS: {
auto it = mAxes.find(rawEvent->code);
@@ -298,16 +301,18 @@
case EV_SYN:
switch (rawEvent->code) {
case SYN_REPORT:
- sync(rawEvent->when, rawEvent->readTime, false /*force*/);
+ out += sync(rawEvent->when, rawEvent->readTime, false /*force*/);
break;
}
break;
}
+ return out;
}
-void JoystickInputMapper::sync(nsecs_t when, nsecs_t readTime, bool force) {
+std::list<NotifyArgs> JoystickInputMapper::sync(nsecs_t when, nsecs_t readTime, bool force) {
+ std::list<NotifyArgs> out;
if (!filterAxes(force)) {
- return;
+ return out;
}
int32_t metaState = getContext()->getGlobalMetaState();
@@ -340,13 +345,14 @@
displayId = getDeviceContext().getAssociatedViewport()->displayId;
}
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(),
- AINPUT_SOURCE_JOYSTICK, displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0,
- AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ AINPUT_SOURCE_JOYSTICK, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &pointerProperties, &pointerCoords, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}));
+ return out;
}
void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis,
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h
index e002397..72b8a52 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.h
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h
@@ -28,10 +28,11 @@
virtual uint32_t getSources() const override;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
virtual void dump(std::string& dump) override;
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) override;
- virtual void reset(nsecs_t when) override;
- virtual void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
private:
struct Axis {
@@ -91,7 +92,7 @@
// Axes indexed by raw ABS_* axis index.
std::unordered_map<int32_t, Axis> mAxes;
- void sync(nsecs_t when, nsecs_t readTime, bool force);
+ [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime, bool force);
bool haveAxis(int32_t axisId);
void pruneAxes(bool ignoreExplicitlyMappedAxes);
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 9bb6273..8704d1b 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -143,9 +143,10 @@
return std::nullopt;
}
-void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
- InputMapper::configure(when, config, changes);
+std::list<NotifyArgs> KeyboardInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) {
+ std::list<NotifyArgs> out = InputMapper::configure(when, config, changes);
if (!changes) { // first time only
// Configure basic parameters.
@@ -155,6 +156,7 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
mViewport = findViewport(when, config);
}
+ return out;
}
static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* property) {
@@ -194,16 +196,18 @@
dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", toString(mParameters.handlesKeyRepeat));
}
-void KeyboardInputMapper::reset(nsecs_t when) {
- cancelAllDownKeys(when);
+std::list<NotifyArgs> KeyboardInputMapper::reset(nsecs_t when) {
+ std::list<NotifyArgs> out = cancelAllDownKeys(when);
mCurrentHidUsage = 0;
resetLedState();
- InputMapper::reset(when);
+ out += InputMapper::reset(when);
+ return out;
}
-void KeyboardInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> KeyboardInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out;
switch (rawEvent->type) {
case EV_KEY: {
int32_t scanCode = rawEvent->code;
@@ -211,8 +215,8 @@
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) {
- processKey(rawEvent->when, rawEvent->readTime, rawEvent->value != 0, scanCode,
- usageCode);
+ out += processKey(rawEvent->when, rawEvent->readTime, rawEvent->value != 0,
+ scanCode, usageCode);
}
break;
}
@@ -228,6 +232,7 @@
}
}
}
+ return out;
}
bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
@@ -265,8 +270,9 @@
return false;
}
-void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, int32_t scanCode,
- int32_t usageCode) {
+std::list<NotifyArgs> KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down,
+ int32_t scanCode, int32_t usageCode) {
+ std::list<NotifyArgs> out;
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
@@ -295,10 +301,10 @@
// key down
if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
- return;
+ return out;
}
if (policyFlags & POLICY_FLAG_GESTURE) {
- getDeviceContext().cancelTouch(when, readTime);
+ out += getDeviceContext().cancelTouch(when, readTime);
}
KeyDown keyDown;
@@ -320,7 +326,7 @@
ALOGI("Dropping key up from device %s because the key was not down. "
"keyCode=%d, scanCode=%d",
getDeviceName().c_str(), keyCode, scanCode);
- return;
+ return out;
}
}
@@ -347,11 +353,12 @@
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
- NotifyKeyArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- getDisplayId(), policyFlags,
- down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
- getListener().notifyKey(&args);
+ out.push_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
+ getDisplayId(), policyFlags,
+ down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState,
+ downTime));
+ return out;
}
ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
@@ -470,19 +477,20 @@
return std::nullopt;
}
-void KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) {
+std::list<NotifyArgs> KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) {
+ std::list<NotifyArgs> out;
size_t n = mKeyDowns.size();
for (size_t i = 0; i < n; i++) {
- NotifyKeyArgs args(getContext()->getNextId(), when, systemTime(SYSTEM_TIME_MONOTONIC),
- getDeviceId(), mSource, getDisplayId(), 0 /*policyFlags*/,
- AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED,
- mKeyDowns[i].keyCode, mKeyDowns[i].scanCode, AMETA_NONE,
- mKeyDowns[i].downTime);
- getListener().notifyKey(&args);
+ out.push_back(NotifyKeyArgs(getContext()->getNextId(), when,
+ systemTime(SYSTEM_TIME_MONOTONIC), getDeviceId(), mSource,
+ getDisplayId(), 0 /*policyFlags*/, AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED,
+ mKeyDowns[i].keyCode, mKeyDowns[i].scanCode, AMETA_NONE,
+ mKeyDowns[i].downTime));
}
mKeyDowns.clear();
mMetaState = AMETA_NONE;
+ return out;
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 2136d25..8d72ee9 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -25,24 +25,25 @@
KeyboardInputMapper(InputDeviceContext& deviceContext, uint32_t source, int32_t keyboardType);
virtual ~KeyboardInputMapper();
- virtual uint32_t getSources() const override;
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
- virtual void dump(std::string& dump) override;
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) override;
- virtual void reset(nsecs_t when) override;
- virtual void process(const RawEvent* rawEvent) override;
+ uint32_t getSources() const override;
+ void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void dump(std::string& dump) override;
+ [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
- virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
- virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
- virtual bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
- uint8_t* outFlags) override;
- virtual int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const override;
+ int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
+ int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
+ bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
+ uint8_t* outFlags) override;
+ int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const override;
- virtual int32_t getMetaState() override;
- virtual bool updateMetaState(int32_t keyCode) override;
- virtual std::optional<int32_t> getAssociatedDisplayId() override;
- virtual void updateLedState(bool reset);
+ int32_t getMetaState() override;
+ bool updateMetaState(int32_t keyCode) override;
+ std::optional<int32_t> getAssociatedDisplayId() override;
+ void updateLedState(bool reset) override;
private:
// The current viewport.
@@ -86,7 +87,8 @@
bool isKeyboardOrGamepadKey(int32_t scanCode);
bool isMediaKey(int32_t keyCode);
- void processKey(nsecs_t when, nsecs_t readTime, bool down, int32_t scanCode, int32_t usageCode);
+ [[nodiscard]] std::list<NotifyArgs> processKey(nsecs_t when, nsecs_t readTime, bool down,
+ int32_t scanCode, int32_t usageCode);
bool updateMetaStateIfNeeded(int32_t keyCode, bool down);
@@ -97,7 +99,7 @@
void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset);
std::optional<DisplayViewport> findViewport(nsecs_t when,
const InputReaderConfiguration* config);
- void cancelAllDownKeys(nsecs_t when);
+ [[nodiscard]] std::list<NotifyArgs> cancelAllDownKeys(nsecs_t when);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 8f5dc9b..1d53eab 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -38,13 +38,9 @@
bool usingSlotsProtocol) {
mUsingSlotsProtocol = usingSlotsProtocol;
mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
-
mSlots = std::vector<Slot>(slotCount);
-}
-void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) {
- // Unfortunately there is no way to read the initial contents of the slots.
- // So when we reset the accumulator, we must assume they are all zeroes.
+ mCurrentSlot = -1;
if (mUsingSlotsProtocol) {
// Query the driver for the current slot index and use it as the initial slot
// before we start reading events from the device. It is possible that the
@@ -56,22 +52,20 @@
// This can cause the touch point to "jump", but at least there will be
// no stuck touches.
int32_t initialSlot;
- status_t status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
- if (status) {
- ALOGD("Could not retrieve current multitouch slot index. status=%d", status);
- initialSlot = -1;
+ if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
+ status == OK) {
+ mCurrentSlot = initialSlot;
+ } else {
+ ALOGD("Could not retrieve current multi-touch slot index. status=%d", status);
}
- clearSlots(initialSlot);
- } else {
- clearSlots(-1);
}
}
-void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
+void MultiTouchMotionAccumulator::resetSlots() {
for (Slot& slot : mSlots) {
slot.clear();
}
- mCurrentSlot = initialSlot;
+ mCurrentSlot = -1;
}
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
@@ -159,7 +153,7 @@
void MultiTouchMotionAccumulator::finishSync() {
if (!mUsingSlotsProtocol) {
- clearSlots(-1);
+ resetSlots();
}
}
@@ -197,18 +191,21 @@
MultiTouchInputMapper::~MultiTouchInputMapper() {}
-void MultiTouchInputMapper::reset(nsecs_t when) {
- mMultiTouchMotionAccumulator.reset(getDeviceContext());
-
- mPointerIdBits.clear();
-
- TouchInputMapper::reset(when);
+std::list<NotifyArgs> MultiTouchInputMapper::reset(nsecs_t when) {
+ // The evdev multi-touch protocol does not allow userspace applications to query the initial or
+ // current state of the pointers at any time. This means if we clear our accumulated state when
+ // resetting the input mapper, there's no way to rebuild the full initial state of the pointers.
+ // We can only wait for updates to all the pointers and axes. Rather than clearing the state and
+ // rebuilding the state from scratch, we work around this kernel API limitation by never
+ // fully clearing any state specific to the multi-touch protocol.
+ return TouchInputMapper::reset(when);
}
-void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
- TouchInputMapper::process(rawEvent);
+std::list<NotifyArgs> MultiTouchInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out = TouchInputMapper::process(rawEvent);
mMultiTouchMotionAccumulator.process(rawEvent);
+ return out;
}
std::optional<int32_t> MultiTouchInputMapper::getActiveBitId(
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 212c9c9..047e62d 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -68,7 +68,6 @@
MultiTouchMotionAccumulator();
void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol);
- void reset(InputDeviceContext& deviceContext);
void process(const RawEvent* rawEvent);
void finishSync();
bool hasStylus() const;
@@ -85,7 +84,7 @@
bool mUsingSlotsProtocol;
bool mHaveStylus;
- void clearSlots(int32_t initialSlot);
+ void resetSlots();
void warnIfNotInUse(const RawEvent& event, const Slot& slot);
};
@@ -94,8 +93,8 @@
explicit MultiTouchInputMapper(InputDeviceContext& deviceContext);
~MultiTouchInputMapper() override;
- void reset(nsecs_t when) override;
- void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
protected:
void syncTouch(nsecs_t when, RawState* outState) override;
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 05973f7..29a1bda 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -60,9 +60,10 @@
toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel()));
}
-void RotaryEncoderInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
- InputMapper::configure(when, config, changes);
+std::list<NotifyArgs> RotaryEncoderInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) {
+ std::list<NotifyArgs> out = InputMapper::configure(when, config, changes);
if (!changes) {
mRotaryEncoderScrollAccumulator.configure(getDeviceContext());
}
@@ -75,23 +76,27 @@
mOrientation = DISPLAY_ORIENTATION_0;
}
}
+ return out;
}
-void RotaryEncoderInputMapper::reset(nsecs_t when) {
+std::list<NotifyArgs> RotaryEncoderInputMapper::reset(nsecs_t when) {
mRotaryEncoderScrollAccumulator.reset(getDeviceContext());
- InputMapper::reset(when);
+ return InputMapper::reset(when);
}
-void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> RotaryEncoderInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out;
mRotaryEncoderScrollAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- sync(rawEvent->when, rawEvent->readTime);
+ out += sync(rawEvent->when, rawEvent->readTime);
}
+ return out;
}
-void RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+std::list<NotifyArgs> RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+ std::list<NotifyArgs> out;
PointerCoords pointerCoords;
pointerCoords.clear();
@@ -121,16 +126,17 @@
int32_t metaState = getContext()->getGlobalMetaState();
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
- NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0,
- 0, metaState, /* buttonState */ 0, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
- getListener().notifyMotion(&scrollArgs);
+ out.push_back(
+ NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+ metaState, /* buttonState */ 0, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}));
}
mRotaryEncoderScrollAccumulator.finishSync();
+ return out;
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
index 42e2421..f4352e7 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
@@ -29,10 +29,11 @@
virtual uint32_t getSources() const override;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
virtual void dump(std::string& dump) override;
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) override;
- virtual void reset(nsecs_t when) override;
- virtual void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
private:
CursorScrollAccumulator mRotaryEncoderScrollAccumulator;
@@ -41,7 +42,7 @@
float mScalingFactor;
int32_t mOrientation;
- void sync(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index 573f99c..d81022f 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -122,9 +122,10 @@
}
}
-void SensorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
- InputMapper::configure(when, config, changes);
+std::list<NotifyArgs> SensorInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) {
+ std::list<NotifyArgs> out = InputMapper::configure(when, config, changes);
if (!changes) { // first time only
mDeviceEnabled = true;
@@ -158,6 +159,7 @@
}
}
}
+ return out;
}
SensorInputMapper::Axis SensorInputMapper::createAxis(const AxisInfo& axisInfo,
@@ -185,7 +187,7 @@
return Axis(rawAxisInfo, axisInfo, scale, offset, min, max, flat, fuzz, resolution, filter);
}
-void SensorInputMapper::reset(nsecs_t when) {
+std::list<NotifyArgs> SensorInputMapper::reset(nsecs_t when) {
// Recenter all axes.
for (std::pair<const int32_t, Axis>& pair : mAxes) {
Axis& axis = pair.second;
@@ -193,7 +195,7 @@
}
mHardwareTimestamp = 0;
mPrevMscTime = 0;
- InputMapper::reset(when);
+ return InputMapper::reset(when);
}
SensorInputMapper::Sensor SensorInputMapper::createSensor(InputDeviceSensorType sensorType,
@@ -256,7 +258,8 @@
mPrevMscTime = static_cast<uint32_t>(mscTime);
}
-void SensorInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> SensorInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out;
switch (rawEvent->type) {
case EV_ABS: {
auto it = mAxes.find(rawEvent->code);
@@ -274,7 +277,7 @@
Axis& axis = pair.second;
axis.currentValue = axis.newValue;
}
- sync(rawEvent->when, false /*force*/);
+ out += sync(rawEvent->when, false /*force*/);
break;
}
break;
@@ -287,6 +290,7 @@
break;
}
}
+ return out;
}
bool SensorInputMapper::setSensorEnabled(InputDeviceSensorType sensorType, bool enabled) {
@@ -375,7 +379,8 @@
}
}
-void SensorInputMapper::sync(nsecs_t when, bool force) {
+std::list<NotifyArgs> SensorInputMapper::sync(nsecs_t when, bool force) {
+ std::list<NotifyArgs> out;
for (auto& [sensorType, sensor] : mSensors) {
// Skip if sensor not enabled
if (!sensor.enabled) {
@@ -405,17 +410,17 @@
// Convert to Android unit
convertFromLinuxToAndroid(values, sensorType);
// Notify dispatcher for sensor event
- NotifySensorArgs args(getContext()->getNextId(), when, getDeviceId(),
- AINPUT_SOURCE_SENSOR, sensorType, sensor.sensorInfo.accuracy,
- sensor.accuracy !=
- sensor.sensorInfo.accuracy /* accuracyChanged */,
- timestamp /* hwTimestamp */, values);
-
- getListener().notifySensor(&args);
+ out.push_back(NotifySensorArgs(getContext()->getNextId(), when, getDeviceId(),
+ AINPUT_SOURCE_SENSOR, sensorType,
+ sensor.sensorInfo.accuracy,
+ sensor.accuracy !=
+ sensor.sensorInfo.accuracy /* accuracyChanged */,
+ timestamp /* hwTimestamp */, values));
sensor.lastSampleTimeNs = timestamp;
sensor.accuracy = sensor.sensorInfo.accuracy;
}
}
+ return out;
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.h b/services/inputflinger/reader/mapper/SensorInputMapper.h
index 38d4c3c..457567b 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.h
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.h
@@ -30,9 +30,11 @@
uint32_t getSources() const override;
void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
void dump(std::string& dump) override;
- void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override;
- void reset(nsecs_t when) override;
- void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
bool enableSensor(InputDeviceSensorType sensorType, std::chrono::microseconds samplingPeriod,
std::chrono::microseconds maxBatchReportLatency) override;
void disableSensor(InputDeviceSensorType sensorType) override;
@@ -116,7 +118,7 @@
// Sensor list
std::unordered_map<InputDeviceSensorType, Sensor> mSensors;
- void sync(nsecs_t when, bool force);
+ [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, bool force);
template <typename T>
bool tryGetProperty(std::string keyName, T& outValue);
diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp
index 4fff9be..13ad224 100644
--- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp
@@ -23,16 +23,17 @@
SingleTouchInputMapper::~SingleTouchInputMapper() {}
-void SingleTouchInputMapper::reset(nsecs_t when) {
+std::list<NotifyArgs> SingleTouchInputMapper::reset(nsecs_t when) {
mSingleTouchMotionAccumulator.reset(getDeviceContext());
- TouchInputMapper::reset(when);
+ return TouchInputMapper::reset(when);
}
-void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
- TouchInputMapper::process(rawEvent);
+std::list<NotifyArgs> SingleTouchInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out = TouchInputMapper::process(rawEvent);
mSingleTouchMotionAccumulator.process(rawEvent);
+ return out;
}
void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
index f54c195..662e6bc 100644
--- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
@@ -26,8 +26,8 @@
explicit SingleTouchInputMapper(InputDeviceContext& deviceContext);
~SingleTouchInputMapper() override;
- void reset(nsecs_t when) override;
- void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
protected:
void syncTouch(nsecs_t when, RawState* outState) override;
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
index ebb5de6..c9101ca 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
@@ -29,7 +29,8 @@
return AINPUT_SOURCE_SWITCH;
}
-void SwitchInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> SwitchInputMapper::process(const RawEvent* rawEvent) {
+ std::list<NotifyArgs> out;
switch (rawEvent->type) {
case EV_SW:
processSwitch(rawEvent->code, rawEvent->value);
@@ -37,9 +38,10 @@
case EV_SYN:
if (rawEvent->code == SYN_REPORT) {
- sync(rawEvent->when);
+ out += sync(rawEvent->when);
}
}
+ return out;
}
void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
@@ -53,15 +55,16 @@
}
}
-void SwitchInputMapper::sync(nsecs_t when) {
+std::list<NotifyArgs> SwitchInputMapper::sync(nsecs_t when) {
+ std::list<NotifyArgs> out;
if (mUpdatedSwitchMask) {
uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
- NotifySwitchArgs args(getContext()->getNextId(), when, 0 /*policyFlags*/,
- updatedSwitchValues, mUpdatedSwitchMask);
- getListener().notifySwitch(&args);
+ out.push_back(NotifySwitchArgs(getContext()->getNextId(), when, 0 /*policyFlags*/,
+ updatedSwitchValues, mUpdatedSwitchMask));
mUpdatedSwitchMask = 0;
}
+ return out;
}
int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.h b/services/inputflinger/reader/mapper/SwitchInputMapper.h
index e0c949f..06d6504 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.h
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.h
@@ -26,7 +26,7 @@
virtual ~SwitchInputMapper();
virtual uint32_t getSources() const override;
- virtual void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode) override;
virtual void dump(std::string& dump) override;
@@ -36,7 +36,7 @@
uint32_t mUpdatedSwitchMask;
void processSwitch(int32_t switchCode, int32_t switchValue);
- void sync(nsecs_t when);
+ [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 42d819b..5a7ba9a 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -71,30 +71,34 @@
AMOTION_EVENT_BUTTON_TERTIARY);
}
-static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nsecs_t when,
- nsecs_t readTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t lastButtonState,
- int32_t currentButtonState, int32_t buttonState, int32_t keyCode) {
+[[nodiscard]] static std::list<NotifyArgs> synthesizeButtonKey(
+ InputReaderContext* context, int32_t action, nsecs_t when, nsecs_t readTime,
+ int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
+ int32_t lastButtonState, int32_t currentButtonState, int32_t buttonState, int32_t keyCode) {
+ std::list<NotifyArgs> out;
if ((action == AKEY_EVENT_ACTION_DOWN && !(lastButtonState & buttonState) &&
(currentButtonState & buttonState)) ||
(action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) &&
!(currentButtonState & buttonState))) {
- NotifyKeyArgs args(context->getNextId(), when, readTime, deviceId, source, displayId,
- policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when);
- context->getListener().notifyKey(&args);
+ out.push_back(NotifyKeyArgs(context->getNextId(), when, readTime, deviceId, source,
+ displayId, policyFlags, action, 0, keyCode, 0,
+ context->getGlobalMetaState(), when));
}
+ return out;
}
-static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, nsecs_t when,
- nsecs_t readTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t lastButtonState,
- int32_t currentButtonState) {
- synthesizeButtonKey(context, action, when, readTime, deviceId, source, displayId, policyFlags,
- lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_BACK,
- AKEYCODE_BACK);
- synthesizeButtonKey(context, action, when, readTime, deviceId, source, displayId, policyFlags,
- lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_FORWARD,
- AKEYCODE_FORWARD);
+[[nodiscard]] static std::list<NotifyArgs> synthesizeButtonKeys(
+ InputReaderContext* context, int32_t action, nsecs_t when, nsecs_t readTime,
+ int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
+ int32_t lastButtonState, int32_t currentButtonState) {
+ std::list<NotifyArgs> out;
+ out += synthesizeButtonKey(context, action, when, readTime, deviceId, source, displayId,
+ policyFlags, lastButtonState, currentButtonState,
+ AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK);
+ out += synthesizeButtonKey(context, action, when, readTime, deviceId, source, displayId,
+ policyFlags, lastButtonState, currentButtonState,
+ AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);
+ return out;
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 4cd2cce..18a73ea 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -189,73 +189,74 @@
void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
InputMapper::populateDeviceInfo(info);
- if (mDeviceMode != DeviceMode::DISABLED) {
- info->addMotionRange(mOrientedRanges.x);
- info->addMotionRange(mOrientedRanges.y);
- info->addMotionRange(mOrientedRanges.pressure);
-
- if (mDeviceMode == DeviceMode::UNSCALED && mSource == AINPUT_SOURCE_TOUCHPAD) {
- // Populate RELATIVE_X and RELATIVE_Y motion ranges for touchpad capture mode.
- //
- // RELATIVE_X and RELATIVE_Y motion ranges should be the largest possible relative
- // motion, i.e. the hardware dimensions, as the finger could move completely across the
- // touchpad in one sample cycle.
- const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
- const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
- info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat,
- x.fuzz, x.resolution);
- info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat,
- y.fuzz, y.resolution);
- }
-
- if (mOrientedRanges.size) {
- info->addMotionRange(*mOrientedRanges.size);
- }
-
- if (mOrientedRanges.touchMajor) {
- info->addMotionRange(*mOrientedRanges.touchMajor);
- info->addMotionRange(*mOrientedRanges.touchMinor);
- }
-
- if (mOrientedRanges.toolMajor) {
- info->addMotionRange(*mOrientedRanges.toolMajor);
- info->addMotionRange(*mOrientedRanges.toolMinor);
- }
-
- if (mOrientedRanges.orientation) {
- info->addMotionRange(*mOrientedRanges.orientation);
- }
-
- if (mOrientedRanges.distance) {
- info->addMotionRange(*mOrientedRanges.distance);
- }
-
- if (mOrientedRanges.tilt) {
- info->addMotionRange(*mOrientedRanges.tilt);
- }
-
- if (mCursorScrollAccumulator.haveRelativeVWheel()) {
- info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
- 0.0f);
- }
- if (mCursorScrollAccumulator.haveRelativeHWheel()) {
- info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
- 0.0f);
- }
- if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
- const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
- const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
- info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat,
- x.fuzz, x.resolution);
- info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat,
- y.fuzz, y.resolution);
- info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat,
- x.fuzz, x.resolution);
- info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat,
- y.fuzz, y.resolution);
- }
- info->setButtonUnderPad(mParameters.hasButtonUnderPad);
+ if (mDeviceMode == DeviceMode::DISABLED) {
+ return;
}
+
+ info->addMotionRange(mOrientedRanges.x);
+ info->addMotionRange(mOrientedRanges.y);
+ info->addMotionRange(mOrientedRanges.pressure);
+
+ if (mDeviceMode == DeviceMode::UNSCALED && mSource == AINPUT_SOURCE_TOUCHPAD) {
+ // Populate RELATIVE_X and RELATIVE_Y motion ranges for touchpad capture mode.
+ //
+ // RELATIVE_X and RELATIVE_Y motion ranges should be the largest possible relative
+ // motion, i.e. the hardware dimensions, as the finger could move completely across the
+ // touchpad in one sample cycle.
+ const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
+ const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
+ info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat, x.fuzz,
+ x.resolution);
+ info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat, y.fuzz,
+ y.resolution);
+ }
+
+ if (mOrientedRanges.size) {
+ info->addMotionRange(*mOrientedRanges.size);
+ }
+
+ if (mOrientedRanges.touchMajor) {
+ info->addMotionRange(*mOrientedRanges.touchMajor);
+ info->addMotionRange(*mOrientedRanges.touchMinor);
+ }
+
+ if (mOrientedRanges.toolMajor) {
+ info->addMotionRange(*mOrientedRanges.toolMajor);
+ info->addMotionRange(*mOrientedRanges.toolMinor);
+ }
+
+ if (mOrientedRanges.orientation) {
+ info->addMotionRange(*mOrientedRanges.orientation);
+ }
+
+ if (mOrientedRanges.distance) {
+ info->addMotionRange(*mOrientedRanges.distance);
+ }
+
+ if (mOrientedRanges.tilt) {
+ info->addMotionRange(*mOrientedRanges.tilt);
+ }
+
+ if (mCursorScrollAccumulator.haveRelativeVWheel()) {
+ info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+ }
+ if (mCursorScrollAccumulator.haveRelativeHWheel()) {
+ info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+ }
+ if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
+ const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
+ const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
+ info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, x.fuzz,
+ x.resolution);
+ info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, y.fuzz,
+ y.resolution);
+ info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, x.fuzz,
+ x.resolution);
+ info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, y.fuzz,
+ y.resolution);
+ }
+ info->setButtonUnderPad(mParameters.hasButtonUnderPad);
+ info->setSupportsUsi(mParameters.supportsUsi);
}
void TouchInputMapper::dump(std::string& dump) {
@@ -346,9 +347,10 @@
}
}
-void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
- InputMapper::configure(when, config, changes);
+std::list<NotifyArgs> TouchInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) {
+ std::list<NotifyArgs> out = InputMapper::configure(when, config, changes);
mConfig = *config;
@@ -394,15 +396,13 @@
}
if (changes && resetNeeded) {
- // If the device needs to be reset, cancel any ongoing gestures and reset the state.
- cancelTouch(when, when);
- reset(when);
+ out += reset(when);
// Send reset, unless this is the first time the device has been configured,
// in which case the reader will call reset itself after all mappers are ready.
- NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
- getListener().notifyDeviceReset(&args);
+ out.emplace_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
}
+ return out;
}
void TouchInputMapper::resolveExternalStylusPresence() {
@@ -506,6 +506,10 @@
// up in your pocket but you can enable it using the input device configuration.
mParameters.wake = getDeviceContext().isExternal();
getDeviceContext().getConfiguration().tryGetProperty("touch.wake", mParameters.wake);
+
+ mParameters.supportsUsi = false;
+ getDeviceContext().getConfiguration().tryGetProperty("touch.supportsUsi",
+ mParameters.supportsUsi);
}
void TouchInputMapper::dumpParameters(std::string& dump) {
@@ -522,6 +526,7 @@
mParameters.uniqueDisplayId.c_str());
dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
dump += INDENT4 "Orientation: " + ftl::enum_string(mParameters.orientation) + "\n";
+ dump += StringPrintf(INDENT4 "SupportsUsi: %s\n", toString(mParameters.supportsUsi));
}
void TouchInputMapper::configureRawPointerAxes() {
@@ -1438,7 +1443,10 @@
mInputDeviceOrientation);
}
-void TouchInputMapper::reset(nsecs_t when) {
+std::list<NotifyArgs> TouchInputMapper::reset(nsecs_t when) {
+ std::list<NotifyArgs> out = cancelTouch(when, when);
+ updateTouchSpots();
+
mCursorButtonAccumulator.reset(getDeviceContext());
mCursorScrollAccumulator.reset(getDeviceContext());
mTouchButtonAccumulator.reset(getDeviceContext());
@@ -1469,7 +1477,7 @@
mPointerController->clearSpots();
}
- InputMapper::reset(when);
+ return out += InputMapper::reset(when);
}
void TouchInputMapper::resetExternalStylus() {
@@ -1484,17 +1492,24 @@
mExternalStylusFusionTimeout = LLONG_MAX;
}
-void TouchInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
+ std::list<NotifyArgs> out;
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- sync(rawEvent->when, rawEvent->readTime);
+ out += sync(rawEvent->when, rawEvent->readTime);
}
+ return out;
}
-void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+std::list<NotifyArgs> TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+ std::list<NotifyArgs> out;
+ if (mDeviceMode == DeviceMode::DISABLED) {
+ // Only save the last pending state when the device is disabled.
+ mRawStatesPending.clear();
+ }
// Push a new state.
mRawStatesPending.emplace_back();
@@ -1539,16 +1554,15 @@
next.rawPointerData.hoveringIdBits.value);
}
- processRawTouches(false /*timeout*/);
+ out += processRawTouches(false /*timeout*/);
+ return out;
}
-void TouchInputMapper::processRawTouches(bool timeout) {
+std::list<NotifyArgs> TouchInputMapper::processRawTouches(bool timeout) {
+ std::list<NotifyArgs> out;
if (mDeviceMode == DeviceMode::DISABLED) {
- // Drop all input if the device is disabled.
- cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);
- mCurrentCookedState.clear();
- updateTouchSpots();
- return;
+ // Do not process raw event while the device is disabled.
+ return out;
}
// Drain any pending touch states. The invariant here is that the mCurrentRawState is always
@@ -1573,7 +1587,7 @@
mCurrentRawState.when = mLastRawState.when;
mCurrentRawState.readTime = mLastRawState.readTime;
}
- cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);
+ out += cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);
}
if (count != 0) {
mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);
@@ -1587,15 +1601,17 @@
ALOGD_IF(DEBUG_STYLUS_FUSION,
"Timeout expired, synthesizing event with new stylus data");
const nsecs_t readTime = when; // consider this synthetic event to be zero latency
- cookAndDispatch(when, readTime);
+ out += cookAndDispatch(when, readTime);
} else if (mExternalStylusFusionTimeout == LLONG_MAX) {
mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
}
}
+ return out;
}
-void TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t readTime) {
+std::list<NotifyArgs> TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t readTime) {
+ std::list<NotifyArgs> out;
// Always start with a clean state.
mCurrentCookedState.clear();
@@ -1621,7 +1637,9 @@
// Consume raw off-screen touches before cooking pointer data.
// If touches are consumed, subsequent code will not receive any pointer data.
- if (consumeRawTouches(when, readTime, policyFlags)) {
+ bool consumed;
+ out += consumeRawTouches(when, readTime, policyFlags, consumed /*byref*/);
+ if (consumed) {
mCurrentRawState.rawPointerData.clear();
}
@@ -1634,9 +1652,9 @@
applyExternalStylusTouchState(when);
// Synthesize key down from raw buttons if needed.
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
- mSource, mViewport.displayId, policyFlags, mLastCookedState.buttonState,
- mCurrentCookedState.buttonState);
+ out += synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
+ mSource, mViewport.displayId, policyFlags,
+ mLastCookedState.buttonState, mCurrentCookedState.buttonState);
// Dispatch the touches either directly or by translation through a pointer on screen.
if (mDeviceMode == DeviceMode::POINTER) {
@@ -1678,15 +1696,15 @@
pointerUsage = PointerUsage::GESTURES;
}
- dispatchPointerUsage(when, readTime, policyFlags, pointerUsage);
+ out += dispatchPointerUsage(when, readTime, policyFlags, pointerUsage);
} else {
if (!mCurrentMotionAborted) {
updateTouchSpots();
- dispatchButtonRelease(when, readTime, policyFlags);
- dispatchHoverExit(when, readTime, policyFlags);
- dispatchTouches(when, readTime, policyFlags);
- dispatchHoverEnterAndMove(when, readTime, policyFlags);
- dispatchButtonPress(when, readTime, policyFlags);
+ out += dispatchButtonRelease(when, readTime, policyFlags);
+ out += dispatchHoverExit(when, readTime, policyFlags);
+ out += dispatchTouches(when, readTime, policyFlags);
+ out += dispatchHoverEnterAndMove(when, readTime, policyFlags);
+ out += dispatchButtonPress(when, readTime, policyFlags);
}
if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
@@ -1695,9 +1713,9 @@
}
// Synthesize key up from raw buttons if needed.
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,
- mViewport.displayId, policyFlags, mLastCookedState.buttonState,
- mCurrentCookedState.buttonState);
+ out += synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(),
+ mSource, mViewport.displayId, policyFlags,
+ mLastCookedState.buttonState, mCurrentCookedState.buttonState);
// Clear some transient state.
mCurrentRawState.rawVScroll = 0;
@@ -1706,6 +1724,7 @@
// Copy current touch to last touch in preparation for the next cycle.
mLastRawState.copyFrom(mCurrentRawState);
mLastCookedState.copyFrom(mCurrentCookedState);
+ return out;
}
void TouchInputMapper::updateTouchSpots() {
@@ -1797,34 +1816,41 @@
return false;
}
-void TouchInputMapper::timeoutExpired(nsecs_t when) {
+std::list<NotifyArgs> TouchInputMapper::timeoutExpired(nsecs_t when) {
+ std::list<NotifyArgs> out;
if (mDeviceMode == DeviceMode::POINTER) {
if (mPointerUsage == PointerUsage::GESTURES) {
// Since this is a synthetic event, we can consider its latency to be zero
const nsecs_t readTime = when;
- dispatchPointerGestures(when, readTime, 0 /*policyFlags*/, true /*isTimeout*/);
+ out += dispatchPointerGestures(when, readTime, 0 /*policyFlags*/, true /*isTimeout*/);
}
} else if (mDeviceMode == DeviceMode::DIRECT) {
if (mExternalStylusFusionTimeout < when) {
- processRawTouches(true /*timeout*/);
+ out += processRawTouches(true /*timeout*/);
} else if (mExternalStylusFusionTimeout != LLONG_MAX) {
getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
}
}
+ return out;
}
-void TouchInputMapper::updateExternalStylusState(const StylusState& state) {
+std::list<NotifyArgs> TouchInputMapper::updateExternalStylusState(const StylusState& state) {
+ std::list<NotifyArgs> out;
mExternalStylusState.copyFrom(state);
if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) {
// We're either in the middle of a fused stream of data or we're waiting on data before
// dispatching the initial down, so go ahead and dispatch now that we have fresh stylus
// data.
mExternalStylusDataPending = true;
- processRawTouches(false /*timeout*/);
+ out += processRawTouches(false /*timeout*/);
}
+ return out;
}
-bool TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags, bool& outConsumed) {
+ outConsumed = false;
+ std::list<NotifyArgs> out;
// Check for release of a virtual key.
if (mCurrentVirtualKey.down) {
if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
@@ -1834,10 +1860,12 @@
ALOGD_IF(DEBUG_VIRTUAL_KEYS,
"VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
- dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
+ out.push_back(dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM |
+ AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY));
}
- return true;
+ outConsumed = true;
+ return out;
}
if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
@@ -1847,7 +1875,8 @@
const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
// Pointer is still within the space of the virtual key.
- return true;
+ outConsumed = true;
+ return out;
}
}
@@ -1859,9 +1888,10 @@
if (!mCurrentVirtualKey.ignored) {
ALOGD_IF(DEBUG_VIRTUAL_KEYS, "VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
- dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY |
- AKEY_EVENT_FLAG_CANCELED);
+ out.push_back(dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM |
+ AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY |
+ AKEY_EVENT_FLAG_CANCELED));
}
}
@@ -1891,13 +1921,15 @@
ALOGD_IF(DEBUG_VIRTUAL_KEYS,
"VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
- dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_DOWN,
- AKEY_EVENT_FLAG_FROM_SYSTEM |
- AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
+ out.push_back(dispatchVirtualKey(when, readTime, policyFlags,
+ AKEY_EVENT_ACTION_DOWN,
+ AKEY_EVENT_FLAG_FROM_SYSTEM |
+ AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY));
}
}
}
- return true;
+ outConsumed = true;
+ return out;
}
}
@@ -1919,44 +1951,50 @@
!mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
getContext()->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
}
- return false;
+ return out;
}
-void TouchInputMapper::dispatchVirtualKey(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags) {
+NotifyKeyArgs TouchInputMapper::dispatchVirtualKey(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags, int32_t keyEventAction,
+ int32_t keyEventFlags) {
int32_t keyCode = mCurrentVirtualKey.keyCode;
int32_t scanCode = mCurrentVirtualKey.scanCode;
nsecs_t downTime = mCurrentVirtualKey.downTime;
int32_t metaState = getContext()->getGlobalMetaState();
policyFlags |= POLICY_FLAG_VIRTUAL;
- NotifyKeyArgs args(getContext()->getNextId(), when, readTime, getDeviceId(),
- AINPUT_SOURCE_KEYBOARD, mViewport.displayId, policyFlags, keyEventAction,
- keyEventFlags, keyCode, scanCode, metaState, downTime);
- getListener().notifyKey(&args);
+ return NotifyKeyArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ AINPUT_SOURCE_KEYBOARD, mViewport.displayId, policyFlags, keyEventAction,
+ keyEventFlags, keyCode, scanCode, metaState, downTime);
}
-void TouchInputMapper::abortTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::abortTouches(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ std::list<NotifyArgs> out;
if (mCurrentMotionAborted) {
// Current motion event was already aborted.
- return;
+ return out;
}
BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
if (!currentIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
int32_t buttonState = mCurrentCookedState.buttonState;
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0,
- metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mCurrentCookedState.cookedPointerData.pointerProperties,
- mCurrentCookedState.cookedPointerData.pointerCoords,
- mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_CANCEL, 0, AMOTION_EVENT_FLAG_CANCELED,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits,
+ -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
mCurrentMotionAborted = true;
}
+ return out;
}
-void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ std::list<NotifyArgs> out;
BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
int32_t metaState = getContext()->getGlobalMetaState();
@@ -1966,13 +2004,14 @@
if (!currentIdBits.isEmpty()) {
// No pointer id changes so this is a move event.
// The listener takes care of batching moves so we don't have to deal with that here.
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0,
- metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mCurrentCookedState.cookedPointerData.pointerProperties,
- mCurrentCookedState.cookedPointerData.pointerCoords,
- mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(
+ dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE,
+ 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits,
+ -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
}
} else {
// There may be pointers going up and pointers going down and pointers moving
@@ -2002,13 +2041,16 @@
if (isCanceled) {
ALOGI("Canceling pointer %d for the palm event was detected.", upId);
}
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0,
- isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0,
- mLastCookedState.cookedPointerData.pointerProperties,
- mLastCookedState.cookedPointerData.pointerCoords,
- mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_POINTER_UP, 0,
+ isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState,
+ buttonState, 0,
+ mLastCookedState.cookedPointerData.pointerProperties,
+ mLastCookedState.cookedPointerData.pointerCoords,
+ mLastCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, upId, mOrientedXPrecision,
+ mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
dispatchedIdBits.clearBit(upId);
mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);
}
@@ -2018,13 +2060,14 @@
// events, they do not generally handle them except when presented in a move event.
if (moveNeeded && !moveIdBits.isEmpty()) {
ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0,
- metaState, buttonState, 0,
- mCurrentCookedState.cookedPointerData.pointerProperties,
- mCurrentCookedState.cookedPointerData.pointerCoords,
- mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, -1, mOrientedXPrecision,
+ mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
}
// Dispatch pointer down events using the new pointer locations.
@@ -2037,62 +2080,75 @@
mDownTime = when;
}
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN,
- 0, 0, metaState, buttonState, 0,
- mCurrentCookedState.cookedPointerData.pointerProperties,
- mCurrentCookedState.cookedPointerData.pointerCoords,
- mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits,
- downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(
+ dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState,
+ 0, mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, downId, mOrientedXPrecision,
+ mOrientedYPrecision, mDownTime, MotionClassification::NONE));
}
}
+ return out;
}
-void TouchInputMapper::dispatchHoverExit(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::dispatchHoverExit(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ std::list<NotifyArgs> out;
if (mSentHoverEnter &&
(mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() ||
!mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) {
int32_t metaState = getContext()->getGlobalMetaState();
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0,
- metaState, mLastCookedState.buttonState, 0,
- mLastCookedState.cookedPointerData.pointerProperties,
- mLastCookedState.cookedPointerData.pointerCoords,
- mLastCookedState.cookedPointerData.idToIndex,
- mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision,
- mOrientedYPrecision, mDownTime, MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
+ mLastCookedState.buttonState, 0,
+ mLastCookedState.cookedPointerData.pointerProperties,
+ mLastCookedState.cookedPointerData.pointerCoords,
+ mLastCookedState.cookedPointerData.idToIndex,
+ mLastCookedState.cookedPointerData.hoveringIdBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
mSentHoverEnter = false;
}
+ return out;
}
-void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, nsecs_t readTime,
- uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ std::list<NotifyArgs> out;
if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() &&
!mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
if (!mSentHoverEnter) {
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER,
- 0, 0, metaState, mCurrentRawState.buttonState, 0,
- mCurrentCookedState.cookedPointerData.pointerProperties,
- mCurrentCookedState.cookedPointerData.pointerCoords,
- mCurrentCookedState.cookedPointerData.idToIndex,
- mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
+ mCurrentRawState.buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
mSentHoverEnter = true;
}
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
- metaState, mCurrentRawState.buttonState, 0,
- mCurrentCookedState.cookedPointerData.pointerProperties,
- mCurrentCookedState.cookedPointerData.pointerCoords,
- mCurrentCookedState.cookedPointerData.idToIndex,
- mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
}
+ return out;
}
-void TouchInputMapper::dispatchButtonRelease(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::dispatchButtonRelease(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ std::list<NotifyArgs> out;
BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState);
const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData);
const int32_t metaState = getContext()->getGlobalMetaState();
@@ -2100,17 +2156,21 @@
while (!releasedButtons.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit());
buttonState &= ~actionButton;
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
- actionButton, 0, metaState, buttonState, 0,
- mCurrentCookedState.cookedPointerData.pointerProperties,
- mCurrentCookedState.cookedPointerData.pointerCoords,
- mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+ metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
}
+ return out;
}
-void TouchInputMapper::dispatchButtonPress(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::dispatchButtonPress(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ std::list<NotifyArgs> out;
BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState);
const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData);
const int32_t metaState = getContext()->getGlobalMetaState();
@@ -2118,14 +2178,16 @@
while (!pressedButtons.isEmpty()) {
int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit());
buttonState |= actionButton;
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS,
- actionButton, 0, metaState, buttonState, 0,
- mCurrentCookedState.cookedPointerData.pointerProperties,
- mCurrentCookedState.cookedPointerData.pointerCoords,
- mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime,
- MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState,
+ buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime,
+ MotionClassification::NONE));
}
+ return out;
}
const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) {
@@ -2407,54 +2469,62 @@
}
}
-void TouchInputMapper::dispatchPointerUsage(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
- PointerUsage pointerUsage) {
+std::list<NotifyArgs> TouchInputMapper::dispatchPointerUsage(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags,
+ PointerUsage pointerUsage) {
+ std::list<NotifyArgs> out;
if (pointerUsage != mPointerUsage) {
- abortPointerUsage(when, readTime, policyFlags);
+ out += abortPointerUsage(when, readTime, policyFlags);
mPointerUsage = pointerUsage;
}
switch (mPointerUsage) {
case PointerUsage::GESTURES:
- dispatchPointerGestures(when, readTime, policyFlags, false /*isTimeout*/);
+ out += dispatchPointerGestures(when, readTime, policyFlags, false /*isTimeout*/);
break;
case PointerUsage::STYLUS:
- dispatchPointerStylus(when, readTime, policyFlags);
+ out += dispatchPointerStylus(when, readTime, policyFlags);
break;
case PointerUsage::MOUSE:
- dispatchPointerMouse(when, readTime, policyFlags);
+ out += dispatchPointerMouse(when, readTime, policyFlags);
break;
case PointerUsage::NONE:
break;
}
+ return out;
}
-void TouchInputMapper::abortPointerUsage(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::abortPointerUsage(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ std::list<NotifyArgs> out;
switch (mPointerUsage) {
case PointerUsage::GESTURES:
- abortPointerGestures(when, readTime, policyFlags);
+ out += abortPointerGestures(when, readTime, policyFlags);
break;
case PointerUsage::STYLUS:
- abortPointerStylus(when, readTime, policyFlags);
+ out += abortPointerStylus(when, readTime, policyFlags);
break;
case PointerUsage::MOUSE:
- abortPointerMouse(when, readTime, policyFlags);
+ out += abortPointerMouse(when, readTime, policyFlags);
break;
case PointerUsage::NONE:
break;
}
mPointerUsage = PointerUsage::NONE;
+ return out;
}
-void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
- bool isTimeout) {
+std::list<NotifyArgs> TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags,
+ bool isTimeout) {
+ std::list<NotifyArgs> out;
// Update current gesture coordinates.
bool cancelPreviousGesture, finishPreviousGesture;
bool sendEvents =
preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture, isTimeout);
if (!sendEvents) {
- return;
+ return {};
}
if (finishPreviousGesture) {
cancelPreviousGesture = false;
@@ -2551,11 +2621,15 @@
BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
if (!dispatchedGestureIdBits.isEmpty()) {
if (cancelPreviousGesture) {
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0,
- flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords,
- mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0,
- mPointerGesture.downTime, classification);
+ const uint32_t cancelFlags = flags | AMOTION_EVENT_FLAG_CANCELED;
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_CANCEL, 0, cancelFlags, metaState,
+ buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.lastGestureProperties,
+ mPointerGesture.lastGestureCoords,
+ mPointerGesture.lastGestureIdToIndex,
+ dispatchedGestureIdBits, -1, 0, 0,
+ mPointerGesture.downTime, classification));
dispatchedGestureIdBits.clear();
} else {
@@ -2569,12 +2643,14 @@
while (!upGestureIdBits.isEmpty()) {
uint32_t id = upGestureIdBits.clearFirstMarkedBit();
- dispatchMotion(when, readTime, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_UP, 0, flags, metaState, buttonState,
- AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties,
- mPointerGesture.lastGestureCoords,
- mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0,
- 0, mPointerGesture.downTime, classification);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_POINTER_UP, 0, flags, metaState,
+ buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.lastGestureProperties,
+ mPointerGesture.lastGestureCoords,
+ mPointerGesture.lastGestureIdToIndex,
+ dispatchedGestureIdBits, id, 0, 0,
+ mPointerGesture.downTime, classification));
dispatchedGestureIdBits.clearBit(id);
}
@@ -2583,12 +2659,13 @@
// Send motion events for all pointers that moved.
if (moveNeeded) {
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, flags,
- metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mPointerGesture.currentGestureProperties,
- mPointerGesture.currentGestureCoords,
- mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0,
- mPointerGesture.downTime, classification);
+ out.push_back(
+ dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0,
+ flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.currentGestureProperties,
+ mPointerGesture.currentGestureCoords,
+ mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1,
+ 0, 0, mPointerGesture.downTime, classification));
}
// Send motion events for all pointers that went down.
@@ -2603,24 +2680,26 @@
mPointerGesture.downTime = when;
}
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN,
- 0, flags, metaState, buttonState, 0,
- mPointerGesture.currentGestureProperties,
- mPointerGesture.currentGestureCoords,
- mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0,
- 0, mPointerGesture.downTime, classification);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, flags, metaState,
+ buttonState, 0, mPointerGesture.currentGestureProperties,
+ mPointerGesture.currentGestureCoords,
+ mPointerGesture.currentGestureIdToIndex,
+ dispatchedGestureIdBits, id, 0, 0,
+ mPointerGesture.downTime, classification));
}
}
// Send motion events for hover.
if (mPointerGesture.currentGestureMode == PointerGesture::Mode::HOVER) {
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
- flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mPointerGesture.currentGestureProperties,
- mPointerGesture.currentGestureCoords,
- mPointerGesture.currentGestureIdToIndex,
- mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime,
- MotionClassification::NONE);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState,
+ buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.currentGestureProperties,
+ mPointerGesture.currentGestureCoords,
+ mPointerGesture.currentGestureIdToIndex,
+ mPointerGesture.currentGestureIdBits, -1, 0, 0,
+ mPointerGesture.downTime, MotionClassification::NONE));
} else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) {
// Synthesize a hover move event after all pointers go up to indicate that
// the pointer is hovering again even if the user is not currently touching
@@ -2640,12 +2719,13 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
const int32_t displayId = mPointerController->getDisplayId();
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags,
- metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
- 0, 0, x, y, mPointerGesture.downTime, /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState,
+ buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, 0, 0, x, y, mPointerGesture.downTime,
+ /* videoFrames */ {}));
}
// Update state.
@@ -2664,22 +2744,28 @@
mPointerGesture.lastGestureIdToIndex[id] = index;
}
}
+ return out;
}
-void TouchInputMapper::abortPointerGestures(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::abortPointerGestures(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
const MotionClassification classification =
mPointerGesture.lastGestureMode == PointerGesture::Mode::SWIPE
? MotionClassification::TWO_FINGER_SWIPE
: MotionClassification::NONE;
+ std::list<NotifyArgs> out;
// Cancel previously dispatches pointers.
if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
int32_t buttonState = mCurrentRawState.buttonState;
- dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0,
- metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords,
- mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1,
- 0, 0, mPointerGesture.downTime, classification);
+ out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_CANCEL, 0, AMOTION_EVENT_FLAG_CANCELED,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.lastGestureProperties,
+ mPointerGesture.lastGestureCoords,
+ mPointerGesture.lastGestureIdToIndex,
+ mPointerGesture.lastGestureIdBits, -1, 0, 0,
+ mPointerGesture.downTime, classification));
}
// Reset the current pointer gesture.
@@ -2691,6 +2777,7 @@
mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
mPointerController->clearSpots();
}
+ return out;
}
bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture,
@@ -3407,7 +3494,8 @@
mPointerController->move(deltaX, deltaY);
}
-void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
mPointerSimple.currentCoords.clear();
mPointerSimple.currentProperties.clear();
@@ -3436,14 +3524,16 @@
hovering = false;
}
- dispatchPointerSimple(when, readTime, policyFlags, down, hovering);
+ return dispatchPointerSimple(when, readTime, policyFlags, down, hovering);
}
-void TouchInputMapper::abortPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
- abortPointerSimple(when, readTime, policyFlags);
+std::list<NotifyArgs> TouchInputMapper::abortPointerStylus(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ return abortPointerSimple(when, readTime, policyFlags);
}
-void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
mPointerSimple.currentCoords.clear();
mPointerSimple.currentProperties.clear();
@@ -3478,17 +3568,22 @@
hovering = false;
}
- dispatchPointerSimple(when, readTime, policyFlags, down, hovering);
+ return dispatchPointerSimple(when, readTime, policyFlags, down, hovering);
}
-void TouchInputMapper::abortPointerMouse(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
- abortPointerSimple(when, readTime, policyFlags);
+std::list<NotifyArgs> TouchInputMapper::abortPointerMouse(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
+ std::list<NotifyArgs> out = abortPointerSimple(when, readTime, policyFlags);
mPointerVelocityControl.reset();
+
+ return out;
}
-void TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
- bool down, bool hovering) {
+std::list<NotifyArgs> TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags, bool down,
+ bool hovering) {
+ std::list<NotifyArgs> out;
int32_t metaState = getContext()->getGlobalMetaState();
if (down || hovering) {
@@ -3508,28 +3603,29 @@
mPointerSimple.down = false;
// Send up.
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
- mLastRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
- &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
- xCursorPosition, yCursorPosition, mPointerSimple.downTime,
- /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0,
+ 0, metaState, mLastRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {}));
}
if (mPointerSimple.hovering && !hovering) {
mPointerSimple.hovering = false;
// Send hover exit.
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0,
- metaState, mLastRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
- &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
- xCursorPosition, yCursorPosition, mPointerSimple.downTime,
- /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
+ mLastRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {}));
}
if (down) {
@@ -3538,25 +3634,26 @@
mPointerSimple.downTime = when;
// Send down.
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
- metaState, mCurrentRawState.buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
- mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
- yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {}));
}
// Send move.
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
- &mPointerSimple.currentCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime, /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE,
+ 0, 0, metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {}));
}
if (hovering) {
@@ -3564,25 +3661,26 @@
mPointerSimple.hovering = true;
// Send hover enter.
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
- metaState, mCurrentRawState.buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
- &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
- mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
- yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {}));
}
// Send hover move.
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
- metaState, mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
- &mPointerSimple.currentCoords, mOrientedXPrecision,
- mOrientedYPrecision, xCursorPosition, yCursorPosition,
- mPointerSimple.downTime, /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(
+ NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
+ displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
+ metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}));
}
if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
@@ -3597,14 +3695,14 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
- mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
- &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
- xCursorPosition, yCursorPosition, mPointerSimple.downTime,
- /* videoFrames */ {});
- getListener().notifyMotion(&args);
+ out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
+ mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL,
+ 0, 0, metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties, &pointerCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime,
+ /* videoFrames */ {}));
}
// Save state.
@@ -3614,23 +3712,23 @@
} else {
mPointerSimple.reset();
}
+ return out;
}
-void TouchInputMapper::abortPointerSimple(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+std::list<NotifyArgs> TouchInputMapper::abortPointerSimple(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags) {
mPointerSimple.currentCoords.clear();
mPointerSimple.currentProperties.clear();
- dispatchPointerSimple(when, readTime, policyFlags, false, false);
+ return dispatchPointerSimple(when, readTime, policyFlags, false, false);
}
-void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
- uint32_t source, int32_t action, int32_t actionButton,
- int32_t flags, int32_t metaState, int32_t buttonState,
- int32_t edgeFlags, const PointerProperties* properties,
- const PointerCoords* coords, const uint32_t* idToIndex,
- BitSet32 idBits, int32_t changedId, float xPrecision,
- float yPrecision, nsecs_t downTime,
- MotionClassification classification) {
+NotifyMotionArgs TouchInputMapper::dispatchMotion(
+ nsecs_t when, nsecs_t readTime, uint32_t policyFlags, uint32_t source, int32_t action,
+ int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState,
+ int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords,
+ const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision,
+ float yPrecision, nsecs_t downTime, MotionClassification classification) {
PointerCoords pointerCoords[MAX_POINTERS];
PointerProperties pointerProperties[MAX_POINTERS];
uint32_t pointerCount = 0;
@@ -3676,12 +3774,11 @@
std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
std::for_each(frames.begin(), frames.end(),
[this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); });
- NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
- policyFlags, action, actionButton, flags, metaState, buttonState,
- classification, edgeFlags, pointerCount, pointerProperties, pointerCoords,
- xPrecision, yPrecision, xCursorPosition, yCursorPosition, downTime,
- std::move(frames));
- getListener().notifyMotion(&args);
+ return NotifyMotionArgs(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
+ policyFlags, action, actionButton, flags, metaState, buttonState,
+ classification, edgeFlags, pointerCount, pointerProperties,
+ pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
+ downTime, std::move(frames));
}
bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
@@ -3714,9 +3811,11 @@
return changed;
}
-void TouchInputMapper::cancelTouch(nsecs_t when, nsecs_t readTime) {
- abortPointerUsage(when, readTime, 0 /*policyFlags*/);
- abortTouches(when, readTime, 0 /* policyFlags*/);
+std::list<NotifyArgs> TouchInputMapper::cancelTouch(nsecs_t when, nsecs_t readTime) {
+ std::list<NotifyArgs> out;
+ out += abortPointerUsage(when, readTime, 0 /*policyFlags*/);
+ out += abortTouches(when, readTime, 0 /* policyFlags*/);
+ return out;
}
// Transform input device coordinates to display panel coordinates.
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 31806e1..7b0327e 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -140,18 +140,21 @@
uint32_t getSources() const override;
void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
void dump(std::string& dump) override;
- void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override;
- void reset(nsecs_t when) override;
- void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
+ const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
uint8_t* outFlags) override;
- void cancelTouch(nsecs_t when, nsecs_t readTime) override;
- void timeoutExpired(nsecs_t when) override;
- void updateExternalStylusState(const StylusState& state) override;
+ [[nodiscard]] std::list<NotifyArgs> cancelTouch(nsecs_t when, nsecs_t readTime) override;
+ [[nodiscard]] std::list<NotifyArgs> timeoutExpired(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> updateExternalStylusState(
+ const StylusState& state) override;
std::optional<int32_t> getAssociatedDisplayId() override;
protected:
@@ -229,6 +232,9 @@
GestureMode gestureMode;
bool wake;
+
+ // Whether the device supports the Universal Stylus Initiative (USI) protocol for styluses.
+ bool supportsUsi;
} mParameters;
// Immutable calibration parameters in parsed form.
@@ -320,6 +326,8 @@
int32_t rawVScroll;
int32_t rawHScroll;
+ explicit inline RawState() { clear(); }
+
void copyFrom(const RawState& other) {
when = other.when;
readTime = other.readTime;
@@ -726,30 +734,42 @@
void initializeOrientedRanges();
void initializeSizeRanges();
- void sync(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
- bool consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
- void processRawTouches(bool timeout);
- void cookAndDispatch(nsecs_t when, nsecs_t readTime);
- void dispatchVirtualKey(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags);
+ [[nodiscard]] std::list<NotifyArgs> consumeRawTouches(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags, bool& outConsumed);
+ [[nodiscard]] std::list<NotifyArgs> processRawTouches(bool timeout);
+ [[nodiscard]] std::list<NotifyArgs> cookAndDispatch(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] NotifyKeyArgs dispatchVirtualKey(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags, int32_t keyEventAction,
+ int32_t keyEventFlags);
- void dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
- void dispatchHoverExit(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
- void dispatchHoverEnterAndMove(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
- void dispatchButtonRelease(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
- void dispatchButtonPress(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchTouches(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchHoverExit(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchHoverEnterAndMove(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchButtonRelease(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchButtonPress(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData);
void cookPointerData();
- void abortTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> abortTouches(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
- void dispatchPointerUsage(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
- PointerUsage pointerUsage);
- void abortPointerUsage(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchPointerUsage(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags,
+ PointerUsage pointerUsage);
+ [[nodiscard]] std::list<NotifyArgs> abortPointerUsage(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
- void dispatchPointerGestures(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
- bool isTimeout);
- void abortPointerGestures(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchPointerGestures(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags,
+ bool isTimeout);
+ [[nodiscard]] std::list<NotifyArgs> abortPointerGestures(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
bool preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture,
bool* outFinishPreviousGesture, bool isTimeout);
@@ -757,15 +777,21 @@
// between the last and current events. Uses a relative motion.
void moveMousePointerFromPointerDelta(nsecs_t when, uint32_t pointerId);
- void dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
- void abortPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchPointerStylus(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> abortPointerStylus(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
- void dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
- void abortPointerMouse(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchPointerMouse(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> abortPointerMouse(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
- void dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uint32_t policyFlags, bool down,
- bool hovering);
- void abortPointerSimple(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
+ [[nodiscard]] std::list<NotifyArgs> dispatchPointerSimple(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags, bool down,
+ bool hovering);
+ [[nodiscard]] std::list<NotifyArgs> abortPointerSimple(nsecs_t when, nsecs_t readTime,
+ uint32_t policyFlags);
bool assignExternalStylusId(const RawState& state, bool timeout);
void applyExternalStylusButtonState(nsecs_t when);
@@ -775,12 +801,12 @@
// If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
// method will take care of setting the index and transmuting the action to DOWN or UP
// it is the first / last pointer to go down / up.
- void dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t policyFlags, uint32_t source,
- int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
- int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties,
- const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
- int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime,
- MotionClassification classification);
+ [[nodiscard]] NotifyMotionArgs dispatchMotion(
+ nsecs_t when, nsecs_t readTime, uint32_t policyFlags, uint32_t source, int32_t action,
+ int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState,
+ int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords,
+ const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision,
+ float yPrecision, nsecs_t downTime, MotionClassification classification);
// Updates pointer coords and properties for pointers with specified ids that have moved.
// Returns true if any of them changed.
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 33db527..7645b12 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -35,16 +35,18 @@
info->setVibrator(true);
}
-void VibratorInputMapper::process(const RawEvent* rawEvent) {
+std::list<NotifyArgs> VibratorInputMapper::process(const RawEvent* rawEvent) {
// TODO: Handle FF_STATUS, although it does not seem to be widely supported.
+ return {};
}
-void VibratorInputMapper::vibrate(const VibrationSequence& sequence, ssize_t repeat,
- int32_t token) {
+std::list<NotifyArgs> VibratorInputMapper::vibrate(const VibrationSequence& sequence,
+ ssize_t repeat, int32_t token) {
if (DEBUG_VIBRATOR) {
ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", getDeviceId(),
sequence.toString().c_str(), repeat, token);
}
+ std::list<NotifyArgs> out;
mVibrating = true;
mSequence = sequence;
@@ -53,19 +55,22 @@
mIndex = -1;
// Request InputReader to notify InputManagerService for vibration started.
- NotifyVibratorStateArgs args(getContext()->getNextId(), systemTime(), getDeviceId(), true);
- getListener().notifyVibratorState(&args);
- nextStep();
+ out.push_back(
+ NotifyVibratorStateArgs(getContext()->getNextId(), systemTime(), getDeviceId(), true));
+ out += nextStep();
+ return out;
}
-void VibratorInputMapper::cancelVibrate(int32_t token) {
+std::list<NotifyArgs> VibratorInputMapper::cancelVibrate(int32_t token) {
if (DEBUG_VIBRATOR) {
ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token);
}
+ std::list<NotifyArgs> out;
if (mVibrating && mToken == token) {
- stopVibrating();
+ out.push_back(stopVibrating());
}
+ return out;
}
bool VibratorInputMapper::isVibrating() {
@@ -76,26 +81,29 @@
return getDeviceContext().getVibratorIds();
}
-void VibratorInputMapper::timeoutExpired(nsecs_t when) {
+std::list<NotifyArgs> VibratorInputMapper::timeoutExpired(nsecs_t when) {
+ std::list<NotifyArgs> out;
if (mVibrating) {
if (when >= mNextStepTime) {
- nextStep();
+ out += nextStep();
} else {
getContext()->requestTimeoutAtTime(mNextStepTime);
}
}
+ return out;
}
-void VibratorInputMapper::nextStep() {
+std::list<NotifyArgs> VibratorInputMapper::nextStep() {
if (DEBUG_VIBRATOR) {
ALOGD("nextStep: index=%d, vibrate deviceId=%d", (int)mIndex, getDeviceId());
}
+ std::list<NotifyArgs> out;
mIndex += 1;
if (size_t(mIndex) >= mSequence.pattern.size()) {
if (mRepeat < 0) {
// We are done.
- stopVibrating();
- return;
+ out.push_back(stopVibrating());
+ return out;
}
mIndex = mRepeat;
}
@@ -122,9 +130,10 @@
if (DEBUG_VIBRATOR) {
ALOGD("nextStep: scheduled timeout in %lldms", element.duration.count());
}
+ return out;
}
-void VibratorInputMapper::stopVibrating() {
+NotifyVibratorStateArgs VibratorInputMapper::stopVibrating() {
mVibrating = false;
if (DEBUG_VIBRATOR) {
ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId());
@@ -132,8 +141,7 @@
getDeviceContext().cancelVibrate();
// Request InputReader to notify InputManagerService for vibration complete.
- NotifyVibratorStateArgs args(getContext()->getNextId(), systemTime(), getDeviceId(), false);
- getListener().notifyVibratorState(&args);
+ return NotifyVibratorStateArgs(getContext()->getNextId(), systemTime(), getDeviceId(), false);
}
void VibratorInputMapper::dump(std::string& dump) {
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h
index 894c573..e98f63a 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.h
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h
@@ -27,13 +27,14 @@
virtual uint32_t getSources() const override;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
- virtual void process(const RawEvent* rawEvent) override;
+ [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
- virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) override;
- virtual void cancelVibrate(int32_t token) override;
+ [[nodiscard]] std::list<NotifyArgs> vibrate(const VibrationSequence& sequence, ssize_t repeat,
+ int32_t token) override;
+ [[nodiscard]] std::list<NotifyArgs> cancelVibrate(int32_t token) override;
virtual bool isVibrating() override;
virtual std::vector<int32_t> getVibratorIds() override;
- virtual void timeoutExpired(nsecs_t when) override;
+ [[nodiscard]] std::list<NotifyArgs> timeoutExpired(nsecs_t when) override;
virtual void dump(std::string& dump) override;
private:
@@ -44,8 +45,8 @@
ssize_t mIndex;
nsecs_t mNextStepTime;
- void nextStep();
- void stopVibrating();
+ [[nodiscard]] std::list<NotifyArgs> nextStep();
+ [[nodiscard]] NotifyVibratorStateArgs stopVibrating();
};
} // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 76500c5..fcbb98f 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -40,12 +40,10 @@
"BlockingQueue_test.cpp",
"EventHub_test.cpp",
"FocusResolver_test.cpp",
- "IInputFlingerQuery.aidl",
"InputProcessor_test.cpp",
"InputProcessorConverter_test.cpp",
"InputDispatcher_test.cpp",
"InputReader_test.cpp",
- "InputFlingerService_test.cpp",
"LatencyTracker_test.cpp",
"PreferStylusOverTouch_test.cpp",
"TestInputListener.cpp",
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
deleted file mode 100644
index 5aeb21f..0000000
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import android.InputChannel;
-import android.gui.FocusRequest;
-import android.gui.WindowInfo;
-
-/** @hide */
-interface IInputFlingerQuery
-{
- /* Test interfaces */
- void getInputChannels(out InputChannel[] channels);
- void resetInputManager();
-}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 7ee6950..985c9c5 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,10 +63,14 @@
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
-// The default pid and uid for windows created by the test.
+// The default pid and uid for windows created on the primary display by the test.
static constexpr int32_t WINDOW_PID = 999;
static constexpr int32_t WINDOW_UID = 1001;
+// The default pid and uid for the windows created on the secondary display by the test.
+static constexpr int32_t SECONDARY_WINDOW_PID = 1010;
+static constexpr int32_t SECONDARY_WINDOW_UID = 1012;
+
// The default policy flags to use for event injection by tests.
static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
@@ -500,11 +504,6 @@
verify(*mFilteredEvent);
mFilteredEvent = nullptr;
}
-
- bool isPerDisplayTouchModeEnabled() {
- // TODO(b/198499018): Make this a regular property once per display touch mode is enabled
- return false;
- }
};
// --- InputDispatcherTest ---
@@ -5461,7 +5460,6 @@
sp<FakeWindowHandle>::make(mApplication, mDispatcher,
"Window without input channel", ADISPLAY_ID_DEFAULT,
std::make_optional<sp<IBinder>>(nullptr) /*token*/);
-
mNoInputWindow->setNoInputChannel(true);
mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
// It's perfectly valid for this window to not have an associated input channel
@@ -6806,44 +6804,67 @@
class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
protected:
std::shared_ptr<FakeApplicationHandle> mApp;
+ std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
sp<FakeWindowHandle> mWindow;
sp<FakeWindowHandle> mSecondWindow;
+ sp<FakeWindowHandle> mThirdWindow;
void SetUp() override {
InputDispatcherTest::SetUp();
mApp = std::make_shared<FakeApplicationHandle>();
+ mSecondaryApp = std::make_shared<FakeApplicationHandle>();
mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFocusable(true);
setFocusedWindow(mWindow);
mSecondWindow =
sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFocusable(true);
+ mThirdWindow =
+ sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
+ "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
+ mThirdWindow->setFocusable(true);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}},
+ {SECOND_DISPLAY_ID, {mThirdWindow}}});
+ mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
mWindow->consumeFocusEvent(true);
- // Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
+ // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
- WINDOW_UID, true /*hasPermission*/, ADISPLAY_ID_DEFAULT)) {
+ WINDOW_UID, true /* hasPermission */,
+ ADISPLAY_ID_DEFAULT)) {
mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
+ mThirdWindow->assertNoEvents();
+ }
+
+ // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
+ if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
+ SECONDARY_WINDOW_UID, true /* hasPermission */,
+ SECOND_DISPLAY_ID)) {
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+ mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
}
}
- void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
+ void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, int32_t pid, int32_t uid,
+ bool hasPermission) {
ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
ADISPLAY_ID_DEFAULT));
mWindow->consumeTouchModeEvent(inTouchMode);
mSecondWindow->consumeTouchModeEvent(inTouchMode);
+ mThirdWindow->assertNoEvents();
}
};
TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
const WindowInfo& windowInfo = *mWindow->getInfo();
- changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
- windowInfo.ownerUid, false /*hasPermission*/);
+ changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
+ windowInfo.ownerPid, windowInfo.ownerUid,
+ false /* hasPermission */);
}
TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
@@ -6863,8 +6884,8 @@
int32_t ownerPid = windowInfo.ownerPid;
int32_t ownerUid = windowInfo.ownerUid;
mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
- changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid,
- true /*hasPermission*/);
+ changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
+ ownerUid, true /*hasPermission*/);
}
TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
@@ -6876,6 +6897,16 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
+ const WindowInfo& windowInfo = *mThirdWindow->getInfo();
+ ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
+ windowInfo.ownerPid, windowInfo.ownerUid,
+ true /*hasPermission*/, SECOND_DISPLAY_ID));
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+ mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
+}
+
TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
// Interact with the window first.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
deleted file mode 100644
index 22ae894..0000000
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <BnInputFlingerQuery.h>
-#include <IInputFlingerQuery.h>
-
-#include <android/os/BnInputFlinger.h>
-#include <android/os/IInputFlinger.h>
-
-#include <binder/Binder.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/Parcel.h>
-#include <binder/ProcessState.h>
-
-#include <input/Input.h>
-#include <input/InputTransport.h>
-
-#include <gtest/gtest.h>
-#include <inttypes.h>
-#include <linux/uinput.h>
-#include <log/log.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <chrono>
-#include <thread>
-#include <unordered_map>
-
-#define TAG "InputFlingerServiceTest"
-
-using android::gui::FocusRequest;
-using android::os::BnInputFlinger;
-using android::os::IInputFlinger;
-
-using std::chrono_literals::operator""ms;
-using std::chrono_literals::operator""s;
-
-namespace android {
-
-static const String16 kTestServiceName = String16("InputFlingerService");
-static const String16 kQueryServiceName = String16("InputFlingerQueryService");
-
-// --- InputFlingerServiceTest ---
-class InputFlingerServiceTest : public testing::Test {
-public:
- void SetUp() override;
- void TearDown() override;
-
-protected:
- void InitializeInputFlinger();
-
- sp<IInputFlinger> mService;
- sp<IInputFlingerQuery> mQuery;
-
-private:
- std::unique_ptr<InputChannel> mServerChannel, mClientChannel;
- std::mutex mLock;
-};
-
-
-class TestInputManager : public BnInputFlinger {
-protected:
- virtual ~TestInputManager(){};
-
-public:
- TestInputManager(){};
-
- binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
-
- status_t dump(int fd, const Vector<String16>& args) override;
-
- binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
- binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
- binder::Status setFocusedWindow(const FocusRequest&) override;
-
- void reset();
-
-private:
- mutable Mutex mLock;
- std::vector<std::shared_ptr<InputChannel>> mInputChannels;
-};
-
-class TestInputQuery : public BnInputFlingerQuery {
-public:
- TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
- binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
- binder::Status resetInputManager() override;
-
-private:
- sp<android::TestInputManager> mManager;
-};
-
-binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannel>* channels) {
- return mManager->getInputChannels(channels);
-}
-
-binder::Status TestInputQuery::resetInputManager() {
- mManager->reset();
- return binder::Status::ok();
-}
-
-binder::Status TestInputManager::createInputChannel(const std::string& name,
- InputChannel* outChannel) {
- AutoMutex _l(mLock);
- std::unique_ptr<InputChannel> serverChannel;
- std::unique_ptr<InputChannel> clientChannel;
- InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
-
- clientChannel->copyTo(*outChannel);
-
- mInputChannels.emplace_back(std::move(serverChannel));
-
- return binder::Status::ok();
-}
-
-binder::Status TestInputManager::removeInputChannel(const sp<IBinder>& connectionToken) {
- AutoMutex _l(mLock);
-
- auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(),
- [&](std::shared_ptr<InputChannel>& c) {
- return c->getConnectionToken() == connectionToken;
- });
- if (it != mInputChannels.end()) {
- mInputChannels.erase(it);
- }
-
- return binder::Status::ok();
-}
-
-status_t TestInputManager::dump(int fd, const Vector<String16>& args) {
- std::string dump;
-
- dump += " InputFlinger dump\n";
-
- ::write(fd, dump.c_str(), dump.size());
- return NO_ERROR;
-}
-
-binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannel>* channels) {
- channels->clear();
- for (std::shared_ptr<InputChannel>& channel : mInputChannels) {
- channels->push_back(*channel);
- }
- return binder::Status::ok();
-}
-
-binder::Status TestInputManager::setFocusedWindow(const FocusRequest& request) {
- return binder::Status::ok();
-}
-
-void TestInputManager::reset() {
- mInputChannels.clear();
-}
-
-void InputFlingerServiceTest::SetUp() {
- InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
- InitializeInputFlinger();
-}
-
-void InputFlingerServiceTest::TearDown() {
- mQuery->resetInputManager();
-}
-
-void InputFlingerServiceTest::InitializeInputFlinger() {
- sp<IBinder> input(defaultServiceManager()->waitForService(kTestServiceName));
- ASSERT_TRUE(input != nullptr);
- mService = interface_cast<IInputFlinger>(input);
-
- input = defaultServiceManager()->waitForService(kQueryServiceName);
- ASSERT_TRUE(input != nullptr);
- mQuery = interface_cast<IInputFlingerQuery>(input);
-}
-
-/**
- * Test InputFlinger service interface createInputChannel
- */
-TEST_F(InputFlingerServiceTest, CreateInputChannelReturnsUnblockedFd) {
- // Test that the unblocked file descriptor flag is kept across processes over binder
- // transactions.
-
- InputChannel channel;
- ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
-
- const base::unique_fd& fd = channel.getFd();
- ASSERT_TRUE(fd.ok());
-
- const int result = fcntl(fd, F_GETFL);
- EXPECT_NE(result, -1);
- EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
-}
-
-TEST_F(InputFlingerServiceTest, CreateInputChannel) {
- InputChannel channel;
- ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
-
- std::vector<::android::InputChannel> channels;
- mQuery->getInputChannels(&channels);
- ASSERT_EQ(channels.size(), 1UL);
- EXPECT_EQ(channels[0].getConnectionToken(), channel.getConnectionToken());
-
- mService->removeInputChannel(channel.getConnectionToken());
- mQuery->getInputChannels(&channels);
- EXPECT_EQ(channels.size(), 0UL);
-}
-
-} // namespace android
-
-int main(int argc, char** argv) {
- pid_t forkPid = fork();
-
- if (forkPid == 0) {
- // Server process
- android::sp<android::TestInputManager> manager =
- android::sp<android::TestInputManager>::make();
- android::sp<android::TestInputQuery> query =
- android::sp<android::TestInputQuery>::make(manager);
-
- android::defaultServiceManager()->addService(android::kTestServiceName, manager,
- false /*allowIsolated*/);
- android::defaultServiceManager()->addService(android::kQueryServiceName, query,
- false /*allowIsolated*/);
- android::ProcessState::self()->startThreadPool();
- android::IPCThreadState::self()->joinThreadPool();
- } else {
- android::ProcessState::self()->startThreadPool();
- ::testing::InitGoogleTest(&argc, argv);
- int result = RUN_ALL_TESTS();
- kill(forkPid, SIGKILL);
- return result;
- }
- return 0;
-}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index b36b498..8ac8dfc 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1190,7 +1190,8 @@
}
}
- void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) override {
+ std::list<NotifyArgs> configure(nsecs_t, const InputReaderConfiguration* config,
+ uint32_t changes) override {
std::scoped_lock<std::mutex> lock(mLock);
mConfigureWasCalled = true;
@@ -1201,19 +1202,22 @@
}
mStateChangedCondition.notify_all();
+ return {};
}
- void reset(nsecs_t) override {
+ std::list<NotifyArgs> reset(nsecs_t) override {
std::scoped_lock<std::mutex> lock(mLock);
mResetWasCalled = true;
mStateChangedCondition.notify_all();
+ return {};
}
- void process(const RawEvent* rawEvent) override {
+ std::list<NotifyArgs> process(const RawEvent* rawEvent) override {
std::scoped_lock<std::mutex> lock(mLock);
mLastEvent = *rawEvent;
mProcessWasCalled = true;
mStateChangedCondition.notify_all();
+ return {};
}
int32_t getKeyCodeState(uint32_t, int32_t keyCode) override {
@@ -2736,7 +2740,7 @@
// Configuration
mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
InputReaderConfiguration config;
- mDevice->configure(ARBITRARY_TIME, &config, 0);
+ std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, &config, 0);
ASSERT_EQ(InputDeviceCountryCode::INTERNATIONAL, mDevice->getDeviceInfo().getCountryCode());
}
@@ -2748,10 +2752,10 @@
TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
// Configuration.
InputReaderConfiguration config;
- mDevice->configure(ARBITRARY_TIME, &config, 0);
+ std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, &config, 0);
// Reset.
- mDevice->reset(ARBITRARY_TIME);
+ unused += mDevice->reset(ARBITRARY_TIME);
NotifyDeviceResetArgs resetArgs;
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
@@ -2807,7 +2811,7 @@
mapper2.setMetaState(AMETA_SHIFT_ON);
InputReaderConfiguration config;
- mDevice->configure(ARBITRARY_TIME, &config, 0);
+ std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, &config, 0);
std::string propertyValue;
ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty("key", propertyValue))
@@ -2818,7 +2822,7 @@
ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled());
// Reset
- mDevice->reset(ARBITRARY_TIME);
+ unused += mDevice->reset(ARBITRARY_TIME);
ASSERT_NO_FATAL_FAILURE(mapper1.assertResetWasCalled());
ASSERT_NO_FATAL_FAILURE(mapper2.assertResetWasCalled());
@@ -2874,7 +2878,7 @@
// Event handling.
RawEvent event;
event.deviceId = EVENTHUB_ID;
- mDevice->process(&event, 1);
+ unused += mDevice->process(&event, 1);
ASSERT_NO_FATAL_FAILURE(mapper1.assertProcessWasCalled());
ASSERT_NO_FATAL_FAILURE(mapper2.assertProcessWasCalled());
@@ -2887,7 +2891,8 @@
mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_TOUCHSCREEN);
// First Configuration.
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+ std::list<NotifyArgs> unused =
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
// Device should be enabled by default.
ASSERT_TRUE(mDevice->isEnabled());
@@ -2897,8 +2902,8 @@
const std::string UNIQUE_ID = "local:1";
mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
// Device should be disabled because it is associated with a specific display via
// input port <-> display port association, but the corresponding display is not found
ASSERT_FALSE(mDevice->isEnabled());
@@ -2907,19 +2912,19 @@
mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, hdmi,
ViewportType::INTERNAL);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
ASSERT_TRUE(mDevice->isEnabled());
// Device should be disabled after set disable.
mFakePolicy->addDisabledDevice(mDevice->getId());
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_ENABLED_STATE);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_ENABLED_STATE);
ASSERT_FALSE(mDevice->isEnabled());
// Device should still be disabled even found the associated display.
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
ASSERT_FALSE(mDevice->isEnabled());
}
@@ -2927,50 +2932,67 @@
// Device should be enabled by default.
mFakePolicy->clearViewports();
mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+ std::list<NotifyArgs> unused =
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
ASSERT_TRUE(mDevice->isEnabled());
// Device should be disabled because it is associated with a specific display, but the
// corresponding display is not found.
mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
ASSERT_FALSE(mDevice->isEnabled());
// Device should be enabled when a display is found.
mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
NO_PORT, ViewportType::INTERNAL);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
ASSERT_TRUE(mDevice->isEnabled());
// Device should be disabled after set disable.
mFakePolicy->addDisabledDevice(mDevice->getId());
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_ENABLED_STATE);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_ENABLED_STATE);
ASSERT_FALSE(mDevice->isEnabled());
// Device should still be disabled even found the associated display.
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
ASSERT_FALSE(mDevice->isEnabled());
}
TEST_F(InputDeviceTest, Configure_UniqueId_CorrectlyMatches) {
mFakePolicy->clearViewports();
mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+ std::list<NotifyArgs> unused =
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
NO_PORT, ViewportType::INTERNAL);
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
ASSERT_EQ(DISPLAY_UNIQUE_ID, mDevice->getAssociatedDisplayUniqueId());
}
+/**
+ * This test reproduces a crash caused by a dangling reference that remains after device is added
+ * and removed. The reference is accessed in InputDevice::dump(..);
+ */
+TEST_F(InputDeviceTest, DumpDoesNotCrash) {
+ constexpr int32_t TEST_EVENTHUB_ID = 10;
+ mFakeEventHub->addDevice(TEST_EVENTHUB_ID, "Test EventHub device", InputDeviceClass::BATTERY);
+
+ InputDevice device(mReader->getContext(), 1 /*id*/, 2 /*generation*/, {} /*identifier*/);
+ device.addEventHubDevice(TEST_EVENTHUB_ID, true /*populateMappers*/);
+ device.removeEventHubDevice(TEST_EVENTHUB_ID);
+ std::string dumpStr, eventHubDevStr;
+ device.dump(dumpStr, eventHubDevStr);
+}
+
// --- InputMapperTest ---
class InputMapperTest : public testing::Test {
@@ -3013,7 +3035,7 @@
mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, key, value);
}
- void configureDevice(uint32_t changes) {
+ std::list<NotifyArgs> configureDevice(uint32_t changes) {
if (!changes ||
(changes &
(InputReaderConfiguration::CHANGE_DISPLAY_INFO |
@@ -3021,9 +3043,14 @@
mReader->requestRefreshConfiguration(changes);
mReader->loopOnce();
}
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+ std::list<NotifyArgs> out =
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
// Loop the reader to flush the input listener queue.
+ for (const NotifyArgs& args : out) {
+ mFakeListener->notify(args);
+ }
mReader->loopOnce();
+ return out;
}
std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
@@ -3045,9 +3072,12 @@
T& addMapperAndConfigure(Args... args) {
T& mapper = mDevice->addMapper<T>(EVENTHUB_ID, args...);
configureDevice(0);
- mDevice->reset(ARBITRARY_TIME);
- mapper.reset(ARBITRARY_TIME);
+ std::list<NotifyArgs> resetArgList = mDevice->reset(ARBITRARY_TIME);
+ resetArgList += mapper.reset(ARBITRARY_TIME);
// Loop the reader to flush the input listener queue.
+ for (const NotifyArgs& loopArgs : resetArgList) {
+ mFakeListener->notify(loopArgs);
+ }
mReader->loopOnce();
return mapper;
}
@@ -3064,8 +3094,8 @@
mFakePolicy->clearViewports();
}
- void process(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t type, int32_t code,
- int32_t value) {
+ std::list<NotifyArgs> process(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t type,
+ int32_t code, int32_t value) {
RawEvent event;
event.when = when;
event.readTime = readTime;
@@ -3073,7 +3103,20 @@
event.type = type;
event.code = code;
event.value = value;
- mapper.process(&event);
+ std::list<NotifyArgs> processArgList = mapper.process(&event);
+ for (const NotifyArgs& args : processArgList) {
+ mFakeListener->notify(args);
+ }
+ // Loop the reader to flush the input listener queue.
+ mReader->loopOnce();
+ return processArgList;
+ }
+
+ void resetMapper(InputMapper& mapper, nsecs_t when) {
+ const auto resetArgs = mapper.reset(when);
+ for (const auto args : resetArgs) {
+ mFakeListener->notify(args);
+ }
// Loop the reader to flush the input listener queue.
mReader->loopOnce();
}
@@ -3151,14 +3194,17 @@
TEST_F(SwitchInputMapperTest, Process) {
SwitchInputMapper& mapper = addMapperAndConfigure<SwitchInputMapper>();
+ std::list<NotifyArgs> out;
+ out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_LID, 1);
+ ASSERT_TRUE(out.empty());
+ out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_JACK_PHYSICAL_INSERT, 1);
+ ASSERT_TRUE(out.empty());
+ out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_HEADPHONE_INSERT, 0);
+ ASSERT_TRUE(out.empty());
+ out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_LID, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_JACK_PHYSICAL_INSERT, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_HEADPHONE_INSERT, 0);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
- NotifySwitchArgs args;
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySwitchWasCalled(&args));
+ ASSERT_EQ(1u, out.size());
+ const NotifySwitchArgs& args = std::get<NotifySwitchArgs>(*out.begin());
ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
ASSERT_EQ((1U << SW_LID) | (1U << SW_JACK_PHYSICAL_INSERT), args.switchValues);
ASSERT_EQ((1U << SW_LID) | (1U << SW_JACK_PHYSICAL_INSERT) | (1 << SW_HEADPHONE_INSERT),
@@ -3205,22 +3251,23 @@
ASSERT_FALSE(mapper.isVibrating());
// Start vibrating
- mapper.vibrate(sequence, -1 /* repeat */, VIBRATION_TOKEN);
+ std::list<NotifyArgs> out = mapper.vibrate(sequence, -1 /* repeat */, VIBRATION_TOKEN);
ASSERT_TRUE(mapper.isVibrating());
// Verify vibrator state listener was notified.
mReader->loopOnce();
- NotifyVibratorStateArgs args;
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyVibratorStateWasCalled(&args));
- ASSERT_EQ(DEVICE_ID, args.deviceId);
- ASSERT_TRUE(args.isOn);
+ ASSERT_EQ(1u, out.size());
+ const NotifyVibratorStateArgs& vibrateArgs = std::get<NotifyVibratorStateArgs>(*out.begin());
+ ASSERT_EQ(DEVICE_ID, vibrateArgs.deviceId);
+ ASSERT_TRUE(vibrateArgs.isOn);
// Stop vibrating
- mapper.cancelVibrate(VIBRATION_TOKEN);
+ out = mapper.cancelVibrate(VIBRATION_TOKEN);
ASSERT_FALSE(mapper.isVibrating());
// Verify vibrator state listener was notified.
mReader->loopOnce();
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyVibratorStateWasCalled(&args));
- ASSERT_EQ(DEVICE_ID, args.deviceId);
- ASSERT_FALSE(args.isOn);
+ ASSERT_EQ(1u, out.size());
+ const NotifyVibratorStateArgs& cancelArgs = std::get<NotifyVibratorStateArgs>(*out.begin());
+ ASSERT_EQ(DEVICE_ID, cancelArgs.deviceId);
+ ASSERT_FALSE(cancelArgs.isOn);
}
// --- SensorInputMapperTest ---
@@ -3876,7 +3923,7 @@
AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
// Meta state should be AMETA_NONE after reset
- mapper.reset(ARBITRARY_TIME);
+ std::list<NotifyArgs> unused = mapper.reset(ARBITRARY_TIME);
ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
// Meta state should be AMETA_NONE with update, as device doesn't have the keys.
mapper.updateMetaState(AKEYCODE_NUM_LOCK);
@@ -3928,8 +3975,10 @@
KeyboardInputMapper& mapper2 =
device2->addMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
- device2->reset(ARBITRARY_TIME);
+ std::list<NotifyArgs> unused =
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ 0 /*changes*/);
+ unused += device2->reset(ARBITRARY_TIME);
// Prepared displays and associated info.
constexpr uint8_t hdmi1 = 0;
@@ -3940,8 +3989,8 @@
mFakePolicy->addInputPortAssociation(USB2, hdmi2);
// No associated display viewport found, should disable the device.
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
ASSERT_FALSE(device2->isEnabled());
// Prepare second display.
@@ -3951,8 +4000,8 @@
setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
SECONDARY_UNIQUE_ID, hdmi2, ViewportType::EXTERNAL);
// Default device will reconfigure above, need additional reconfiguration for another device.
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
// Device should be enabled after the associated display is found.
ASSERT_TRUE(mDevice->isEnabled());
@@ -4036,8 +4085,10 @@
KeyboardInputMapper& mapper2 =
device2->addMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
- device2->reset(ARBITRARY_TIME);
+ std::list<NotifyArgs> unused =
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ 0 /*changes*/);
+ unused += device2->reset(ARBITRARY_TIME);
ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_CAPSL));
ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_NUML));
@@ -4095,8 +4146,10 @@
KeyboardInputMapper& mapper2 =
device2->addMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
- device2->reset(ARBITRARY_TIME);
+ std::list<NotifyArgs> unused =
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ 0 /*changes*/);
+ unused += device2->reset(ARBITRARY_TIME);
// Initial metastate is AMETA_NONE.
ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
@@ -6820,6 +6873,55 @@
toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
}
+TEST_F(SingleTouchInputMapperTest, Reset_CancelsOngoingGesture) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
+ prepareAxes(POSITION | PRESSURE);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+
+ // Touch down.
+ processDown(mapper, 100, 200);
+ processPressure(mapper, 1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+
+ // Reset the mapper. This should cancel the ongoing gesture.
+ resetMapper(mapper, ARBITRARY_TIME);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)));
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Reset_RecreatesTouchState) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
+ prepareAxes(POSITION | PRESSURE);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+
+ // Set the initial state for the touch pointer.
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_X, 100);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_Y, 200);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_PRESSURE, RAW_PRESSURE_MAX);
+ mFakeEventHub->setScanCodeState(EVENTHUB_ID, BTN_TOUCH, 1);
+
+ // Reset the mapper. When the mapper is reset, we expect it to attempt to recreate the touch
+ // state by reading the current axis values. Since there was no ongoing gesture, calling reset
+ // does not generate any events.
+ resetMapper(mapper, ARBITRARY_TIME);
+
+ // Send a sync to simulate an empty touch frame where nothing changes. The mapper should use
+ // the recreated touch state to generate a down event.
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPressure(1.f))));
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
TEST_F(SingleTouchInputMapperTest,
Process_WhenViewportDisplayIdChanged_TouchIsCanceledAndDeviceIsReset) {
addConfigurationProperty("touch.deviceType", "touchScreen");
@@ -6879,10 +6981,17 @@
// No events are generated while the viewport is inactive.
processMove(mapper, 101, 201);
processSync(mapper);
- processDown(mapper, 102, 202);
+ processUp(mapper);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+ // Start a new gesture while the viewport is still inactive.
+ processDown(mapper, 300, 400);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_X, 300);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_Y, 400);
+ mFakeEventHub->setScanCodeState(EVENTHUB_ID, BTN_TOUCH, 1);
+ processSync(mapper);
+
// Make the viewport active again. The device should resume processing events.
viewport->isActive = true;
mFakePolicy->updateViewport(*viewport);
@@ -6892,11 +7001,10 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
- // Start a new gesture.
- processDown(mapper, 100, 200);
+ // In the next sync, the touch state that was recreated when the device was reset is reported.
processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
// No more events.
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
@@ -8812,8 +8920,10 @@
// Setup the second touch screen device.
MultiTouchInputMapper& mapper2 = device2->addMapper<MultiTouchInputMapper>(SECOND_EVENTHUB_ID);
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
- device2->reset(ARBITRARY_TIME);
+ std::list<NotifyArgs> unused =
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ 0 /*changes*/);
+ unused += device2->reset(ARBITRARY_TIME);
// Setup PointerController.
std::shared_ptr<FakePointerController> fakePointerController =
@@ -8832,9 +8942,9 @@
prepareSecondaryDisplay(ViewportType::EXTERNAL, hdmi2);
// Default device will reconfigure above, need additional reconfiguration for another device.
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO |
- InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
+ unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO |
+ InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
// Two fingers down at default display.
int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
@@ -8864,8 +8974,8 @@
// Disable the show touches configuration and ensure the spots are cleared.
mFakePolicy->setShowTouches(false);
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
+ unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
ASSERT_TRUE(fakePointerController->getSpots().empty());
}
@@ -9428,6 +9538,75 @@
ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
}
+TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | PRESSURE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // First finger down.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, 100, 200);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+
+ // Second finger down.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, 300, 400);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(
+ mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(ACTION_POINTER_1_DOWN)));
+
+ // Reset the mapper. When the mapper is reset, we expect the current multi-touch state to be
+ // preserved. Resetting should cancel the ongoing gesture.
+ resetMapper(mapper, ARBITRARY_TIME);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)));
+
+ // Send a sync to simulate an empty touch frame where nothing changes. The mapper should use
+ // the existing touch state to generate a down event.
+ processPosition(mapper, 301, 302);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPressure(1.f))));
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(ACTION_POINTER_1_DOWN), WithPressure(1.f))));
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
+TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState_NoPointersDown) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | PRESSURE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // First finger touches down and releases.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, 100, 200);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+ processId(mapper, INVALID_TRACKING_ID);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(
+ mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(AMOTION_EVENT_ACTION_UP)));
+
+ // Reset the mapper. When the mapper is reset, we expect it to restore the latest
+ // raw state where no pointers are down.
+ resetMapper(mapper, ARBITRARY_TIME);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // Send an empty sync frame. Since there are no pointers, no events are generated.
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
// --- MultiTouchInputMapperTest_ExternalDevice ---
class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest {
@@ -10034,12 +10213,12 @@
mFakePolicy.clear();
}
- void configureDevice(uint32_t changes) {
+ std::list<NotifyArgs> configureDevice(uint32_t changes) {
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
mReader->requestRefreshConfiguration(changes);
mReader->loopOnce();
}
- mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+ return mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
}
std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
diff --git a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
index 8e2ab88..bd05360 100644
--- a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
+++ b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
@@ -33,14 +33,8 @@
constexpr int32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN;
constexpr int32_t STYLUS = AINPUT_SOURCE_STYLUS;
-struct PointerData {
- float x;
- float y;
-};
-
static NotifyMotionArgs generateMotionArgs(nsecs_t downTime, nsecs_t eventTime, int32_t action,
- const std::vector<PointerData>& points,
- uint32_t source) {
+ const std::vector<Point>& points, uint32_t source) {
size_t pointerCount = points.size();
if (action == DOWN || action == UP) {
EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 57b382c..29093ef 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -147,7 +147,7 @@
}
template <class NotifyArgsType>
-void TestInputListener::notify(const NotifyArgsType* args) {
+void TestInputListener::addToQueue(const NotifyArgsType* args) {
std::scoped_lock<std::mutex> lock(mLock);
std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
@@ -156,35 +156,35 @@
}
void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
- notify<NotifyConfigurationChangedArgs>(args);
+ addToQueue<NotifyConfigurationChangedArgs>(args);
}
void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- notify<NotifyDeviceResetArgs>(args);
+ addToQueue<NotifyDeviceResetArgs>(args);
}
void TestInputListener::notifyKey(const NotifyKeyArgs* args) {
- notify<NotifyKeyArgs>(args);
+ addToQueue<NotifyKeyArgs>(args);
}
void TestInputListener::notifyMotion(const NotifyMotionArgs* args) {
- notify<NotifyMotionArgs>(args);
+ addToQueue<NotifyMotionArgs>(args);
}
void TestInputListener::notifySwitch(const NotifySwitchArgs* args) {
- notify<NotifySwitchArgs>(args);
+ addToQueue<NotifySwitchArgs>(args);
}
void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
- notify<NotifyPointerCaptureChangedArgs>(args);
+ addToQueue<NotifyPointerCaptureChangedArgs>(args);
}
void TestInputListener::notifySensor(const NotifySensorArgs* args) {
- notify<NotifySensorArgs>(args);
+ addToQueue<NotifySensorArgs>(args);
}
void TestInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) {
- notify<NotifyVibratorStateArgs>(args);
+ addToQueue<NotifyVibratorStateArgs>(args);
}
} // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index cad698f..4ad1c42 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -67,7 +67,7 @@
void assertNotCalled(std::string message);
template <class NotifyArgsType>
- void notify(const NotifyArgsType* args);
+ void addToQueue(const NotifyArgsType* args);
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
index 03736a3..ff7455b 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -23,13 +23,19 @@
namespace android {
MATCHER_P(WithMotionAction, action, "InputEvent with specified action") {
- if (action == AMOTION_EVENT_ACTION_CANCEL) {
- *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set";
- return (arg.flags & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ bool matches = action == arg.action;
+ if (!matches) {
+ *result_listener << "expected action " << MotionEvent::actionToString(action)
+ << ", but got " << MotionEvent::actionToString(arg.action);
}
- *result_listener << "expected action " << MotionEvent::actionToString(action) << ", but got "
- << MotionEvent::actionToString(arg.action);
- return action == arg.action;
+ if (action == AMOTION_EVENT_ACTION_CANCEL) {
+ if (!matches) {
+ *result_listener << "; ";
+ }
+ *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set";
+ matches &= (arg.flags & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ }
+ return matches;
}
MATCHER_P(WithSource, source, "InputEvent with specified source") {
@@ -50,6 +56,12 @@
return argX == x && argY == y;
}
+MATCHER_P(WithPressure, pressure, "InputEvent with specified pressure") {
+ const auto argPressure = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
+ *result_listener << "expected pressure " << pressure << ", but got " << pressure;
+ return argPressure;
+}
+
MATCHER_P(WithFlags, flags, "InputEvent with specified flags") {
*result_listener << "expected flags " << flags << ", but got " << arg.flags;
return arg.flags == flags;
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index f4ecba2..55c2db6 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -21,7 +21,6 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-
cc_fuzz {
name: "inputflinger_latencytracker_fuzzer",
defaults: [
@@ -34,7 +33,6 @@
"libbase",
"libbinder",
"liblog",
- "libui",
"libutils",
"libinput",
"libinputflinger",
@@ -43,7 +41,7 @@
"LatencyTrackerFuzzer.cpp",
],
fuzz_config: {
- cc: ["android-framework-input@google.com"],
+ cc: ["android-framework-input@google.com"],
},
}
@@ -63,7 +61,6 @@
"libcutils",
"liblog",
"libutils",
- "libui",
"libinput",
"libinputflinger",
"libinputreader",
@@ -75,7 +72,7 @@
"libinputreader_headers",
],
fuzz_config: {
- cc: ["android-framework-input@google.com"],
+ cc: ["android-framework-input@google.com"],
},
}
diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
index 4b542aa..cc523e1 100644
--- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
@@ -51,12 +51,14 @@
},
[&]() -> void { mapper.getSources(); },
[&]() -> void {
- mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
- fdp->ConsumeIntegral<int32_t>());
+ std::list<NotifyArgs> unused =
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<int32_t>());
},
[&]() -> void {
// Need to reconfigure with 0 or you risk a NPE.
- mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ std::list<NotifyArgs> unused =
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
InputDeviceInfo info;
mapper.populateDeviceInfo(&info);
},
@@ -68,23 +70,27 @@
: fdp->ConsumeIntegral<int32_t>();
// Need to reconfigure with 0 or you risk a NPE.
- mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ std::list<NotifyArgs> unused =
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
fdp->ConsumeIntegral<nsecs_t>(),
fdp->ConsumeIntegral<int32_t>(),
type,
code,
fdp->ConsumeIntegral<int32_t>()};
- mapper.process(&rawEvent);
+ unused += mapper.process(&rawEvent);
},
- [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ std::list<NotifyArgs> unused = mapper.reset(fdp->ConsumeIntegral<nsecs_t>());
+ },
[&]() -> void {
mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(),
fdp->ConsumeIntegral<int32_t>());
},
[&]() -> void {
// Need to reconfigure with 0 or you risk a NPE.
- mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ std::list<NotifyArgs> unused =
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
mapper.getAssociatedDisplayId();
},
})();
diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h
index 62615d0..1e0764f 100644
--- a/services/inputflinger/tests/fuzzers/FuzzContainer.h
+++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h
@@ -27,7 +27,7 @@
class FuzzContainer {
std::shared_ptr<FuzzEventHub> mFuzzEventHub;
sp<FuzzInputReaderPolicy> mFuzzPolicy;
- std::unique_ptr<FuzzInputListener> mFuzzListener;
+ FuzzInputListener mFuzzListener;
std::unique_ptr<FuzzInputReaderContext> mFuzzContext;
std::unique_ptr<InputDevice> mFuzzDevice;
InputReaderConfiguration mPolicyConfig;
@@ -44,9 +44,8 @@
// Create mocked objects.
mFuzzEventHub = std::make_shared<FuzzEventHub>(mFdp);
mFuzzPolicy = sp<FuzzInputReaderPolicy>::make(mFdp);
- mFuzzListener = std::make_unique<FuzzInputListener>();
mFuzzContext = std::make_unique<FuzzInputReaderContext>(mFuzzEventHub, mFuzzPolicy,
- *mFuzzListener, mFdp);
+ mFuzzListener, mFdp);
InputDeviceIdentifier identifier;
identifier.name = deviceName;
@@ -60,8 +59,12 @@
void configureDevice() {
nsecs_t arbitraryTime = mFdp->ConsumeIntegral<nsecs_t>();
- mFuzzDevice->configure(arbitraryTime, &mPolicyConfig, 0);
- mFuzzDevice->reset(arbitraryTime);
+ std::list<NotifyArgs> out;
+ out += mFuzzDevice->configure(arbitraryTime, &mPolicyConfig, 0);
+ out += mFuzzDevice->reset(arbitraryTime);
+ for (const NotifyArgs& args : out) {
+ mFuzzListener.notify(args);
+ }
}
void addProperty(std::string key, std::string value) {
diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
index c48a099..e880f55 100644
--- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
@@ -63,10 +63,13 @@
},
[&]() -> void { mapper.getSources(); },
[&]() -> void {
- mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
- fdp->ConsumeIntegral<uint32_t>());
+ std::list<NotifyArgs> unused =
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<uint32_t>());
},
- [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ std::list<NotifyArgs> unused = mapper.reset(fdp->ConsumeIntegral<nsecs_t>());
+ },
[&]() -> void {
int32_t type, code;
type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
@@ -79,7 +82,7 @@
type,
code,
fdp->ConsumeIntegral<int32_t>()};
- mapper.process(&rawEvent);
+ std::list<NotifyArgs> unused = mapper.process(&rawEvent);
},
[&]() -> void {
mapper.getKeyCodeState(fdp->ConsumeIntegral<uint32_t>(),
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 03c2266..bd81761 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -332,7 +332,6 @@
class FuzzInputReaderContext : public InputReaderContext {
std::shared_ptr<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
- InputListenerInterface& mListener;
std::shared_ptr<FuzzedDataProvider> mFdp;
public:
@@ -340,7 +339,7 @@
const sp<InputReaderPolicyInterface>& policy,
InputListenerInterface& listener,
std::shared_ptr<FuzzedDataProvider> mFdp)
- : mEventHub(eventHub), mPolicy(policy), mListener(listener), mFdp(mFdp) {}
+ : mEventHub(eventHub), mPolicy(policy), mFdp(mFdp) {}
~FuzzInputReaderContext() {}
void updateGlobalMetaState() override {}
int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); }
@@ -355,9 +354,10 @@
void requestTimeoutAtTime(nsecs_t when) override {}
int32_t bumpGeneration() override { return mFdp->ConsumeIntegral<int32_t>(); }
void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override {}
- void dispatchExternalStylusState(const StylusState& outState) override {}
+ std::list<NotifyArgs> dispatchExternalStylusState(const StylusState& outState) override {
+ return {};
+ }
InputReaderPolicyInterface* getPolicy() override { return mPolicy.get(); }
- InputListenerInterface& getListener() override { return mListener; }
EventHubInterface* getEventHub() override { return mEventHub.get(); }
int32_t getNextId() override { return mFdp->ConsumeIntegral<int32_t>(); }
diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
index 59b0642..99fd083 100644
--- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
@@ -78,10 +78,13 @@
},
[&]() -> void { mapper.getSources(); },
[&]() -> void {
- mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
- fdp->ConsumeIntegral<uint32_t>());
+ std::list<NotifyArgs> unused =
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<uint32_t>());
},
- [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ std::list<NotifyArgs> unused = mapper.reset(fdp->ConsumeIntegral<nsecs_t>());
+ },
[&]() -> void {
int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
: fdp->ConsumeIntegral<int32_t>();
@@ -93,7 +96,7 @@
type,
code,
fdp->ConsumeIntegral<int32_t>()};
- mapper.process(&rawEvent);
+ std::list<NotifyArgs> unused = mapper.process(&rawEvent);
},
[&]() -> void {
mapper.getKeyCodeState(fdp->ConsumeIntegral<uint32_t>(),
@@ -113,16 +116,20 @@
nullptr);
},
[&]() -> void {
- mapper.cancelTouch(fdp->ConsumeIntegral<nsecs_t>(),
- fdp->ConsumeIntegral<nsecs_t>());
+ std::list<NotifyArgs> unused =
+ mapper.cancelTouch(fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>());
},
- [&]() -> void { mapper.timeoutExpired(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ std::list<NotifyArgs> unused =
+ mapper.timeoutExpired(fdp->ConsumeIntegral<nsecs_t>());
+ },
[&]() -> void {
StylusState state{fdp->ConsumeIntegral<nsecs_t>(),
fdp->ConsumeFloatingPoint<float>(),
fdp->ConsumeIntegral<uint32_t>(),
fdp->ConsumeIntegral<int32_t>()};
- mapper.updateExternalStylusState(state);
+ std::list<NotifyArgs> unused = mapper.updateExternalStylusState(state);
},
[&]() -> void { mapper.getAssociatedDisplayId(); },
})();
diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
index e76bd72..7416ce9 100644
--- a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
@@ -46,7 +46,7 @@
type,
code,
fdp->ConsumeIntegral<int32_t>()};
- mapper.process(&rawEvent);
+ std::list<NotifyArgs> unused = mapper.process(&rawEvent);
},
[&]() -> void {
mapper.getSwitchState(fdp->ConsumeIntegral<uint32_t>(),
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index 6fbba3f..b7de619 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -38,6 +38,8 @@
"libutils",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
+ "android.hardware.power@1.2",
+ "android.hardware.power@1.3",
"android.hardware.power-V3-cpp",
],
diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp
index 8c225d5..f89035f 100644
--- a/services/powermanager/PowerHalController.cpp
+++ b/services/powermanager/PowerHalController.cpp
@@ -33,16 +33,20 @@
// -------------------------------------------------------------------------------------------------
std::unique_ptr<HalWrapper> HalConnector::connect() {
- sp<IPower> halAidl = PowerHalLoader::loadAidl();
- if (halAidl) {
+ if (sp<IPower> halAidl = PowerHalLoader::loadAidl()) {
return std::make_unique<AidlHalWrapper>(halAidl);
}
- sp<V1_0::IPower> halHidlV1_0 = PowerHalLoader::loadHidlV1_0();
- sp<V1_1::IPower> halHidlV1_1 = PowerHalLoader::loadHidlV1_1();
- if (halHidlV1_1) {
- return std::make_unique<HidlHalWrapperV1_1>(halHidlV1_0, halHidlV1_1);
- }
- if (halHidlV1_0) {
+ // If V1_0 isn't defined, none of them are
+ if (sp<V1_0::IPower> halHidlV1_0 = PowerHalLoader::loadHidlV1_0()) {
+ if (sp<V1_3::IPower> halHidlV1_3 = PowerHalLoader::loadHidlV1_3()) {
+ return std::make_unique<HidlHalWrapperV1_3>(halHidlV1_3);
+ }
+ if (sp<V1_2::IPower> halHidlV1_2 = PowerHalLoader::loadHidlV1_2()) {
+ return std::make_unique<HidlHalWrapperV1_2>(halHidlV1_2);
+ }
+ if (sp<V1_1::IPower> halHidlV1_1 = PowerHalLoader::loadHidlV1_1()) {
+ return std::make_unique<HidlHalWrapperV1_1>(halHidlV1_1);
+ }
return std::make_unique<HidlHalWrapperV1_0>(halHidlV1_0);
}
return nullptr;
diff --git a/services/powermanager/PowerHalLoader.cpp b/services/powermanager/PowerHalLoader.cpp
index 1f1b43a..6bd40f8 100644
--- a/services/powermanager/PowerHalLoader.cpp
+++ b/services/powermanager/PowerHalLoader.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "PowerHalLoader"
#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/1.2/IPower.h>
+#include <android/hardware/power/1.3/IPower.h>
#include <android/hardware/power/IPower.h>
#include <binder/IServiceManager.h>
#include <hardware/power.h>
@@ -55,12 +57,16 @@
sp<IPower> PowerHalLoader::gHalAidl = nullptr;
sp<V1_0::IPower> PowerHalLoader::gHalHidlV1_0 = nullptr;
sp<V1_1::IPower> PowerHalLoader::gHalHidlV1_1 = nullptr;
+sp<V1_2::IPower> PowerHalLoader::gHalHidlV1_2 = nullptr;
+sp<V1_3::IPower> PowerHalLoader::gHalHidlV1_3 = nullptr;
void PowerHalLoader::unloadAll() {
std::lock_guard<std::mutex> lock(gHalMutex);
gHalAidl = nullptr;
gHalHidlV1_0 = nullptr;
gHalHidlV1_1 = nullptr;
+ gHalHidlV1_2 = nullptr;
+ gHalHidlV1_3 = nullptr;
}
sp<IPower> PowerHalLoader::loadAidl() {
@@ -82,6 +88,20 @@
return loadHal<V1_1::IPower>(gHalExists, gHalHidlV1_1, loadFn, "HIDL v1.1");
}
+sp<V1_2::IPower> PowerHalLoader::loadHidlV1_2() {
+ std::lock_guard<std::mutex> lock(gHalMutex);
+ static bool gHalExists = true;
+ static auto loadFn = []() { return V1_2::IPower::castFrom(loadHidlV1_0Locked()); };
+ return loadHal<V1_2::IPower>(gHalExists, gHalHidlV1_2, loadFn, "HIDL v1.2");
+}
+
+sp<V1_3::IPower> PowerHalLoader::loadHidlV1_3() {
+ std::lock_guard<std::mutex> lock(gHalMutex);
+ static bool gHalExists = true;
+ static auto loadFn = []() { return V1_3::IPower::castFrom(loadHidlV1_0Locked()); };
+ return loadHal<V1_3::IPower>(gHalExists, gHalHidlV1_3, loadFn, "HIDL v1.3");
+}
+
sp<V1_0::IPower> PowerHalLoader::loadHidlV1_0Locked() {
static bool gHalExists = true;
static auto loadFn = []() { return V1_0::IPower::getService(); };
diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp
index d74bd23..9e7adf8 100644
--- a/services/powermanager/PowerHalWrapper.cpp
+++ b/services/powermanager/PowerHalWrapper.cpp
@@ -24,8 +24,6 @@
#include <cinttypes>
using namespace android::hardware::power;
-namespace V1_0 = android::hardware::power::V1_0;
-namespace V1_1 = android::hardware::power::V1_1;
namespace Aidl = android::hardware::power;
namespace android {
@@ -108,7 +106,7 @@
HalResult<void> HidlHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) {
if (boost == Boost::INTERACTION) {
- return sendPowerHint(V1_0::PowerHint::INTERACTION, durationMs);
+ return sendPowerHint(V1_3::PowerHint::INTERACTION, durationMs);
} else {
ALOGV("Skipped setBoost %s because Power HAL AIDL not available", toString(boost).c_str());
return HalResult<void>::unsupported();
@@ -119,13 +117,13 @@
uint32_t data = enabled ? 1 : 0;
switch (mode) {
case Mode::LAUNCH:
- return sendPowerHint(V1_0::PowerHint::LAUNCH, data);
+ return sendPowerHint(V1_3::PowerHint::LAUNCH, data);
case Mode::LOW_POWER:
- return sendPowerHint(V1_0::PowerHint::LOW_POWER, data);
+ return sendPowerHint(V1_3::PowerHint::LOW_POWER, data);
case Mode::SUSTAINED_PERFORMANCE:
- return sendPowerHint(V1_0::PowerHint::SUSTAINED_PERFORMANCE, data);
+ return sendPowerHint(V1_3::PowerHint::SUSTAINED_PERFORMANCE, data);
case Mode::VR:
- return sendPowerHint(V1_0::PowerHint::VR_MODE, data);
+ return sendPowerHint(V1_3::PowerHint::VR_MODE, data);
case Mode::INTERACTIVE:
return setInteractive(enabled);
case Mode::DOUBLE_TAP_TO_WAKE:
@@ -137,8 +135,8 @@
}
}
-HalResult<void> HidlHalWrapperV1_0::sendPowerHint(V1_0::PowerHint hintId, uint32_t data) {
- auto ret = mHandleV1_0->powerHint(hintId, data);
+HalResult<void> HidlHalWrapperV1_0::sendPowerHint(V1_3::PowerHint hintId, uint32_t data) {
+ auto ret = mHandleV1_0->powerHint(static_cast<V1_0::PowerHint>(hintId), data);
return HalResult<void>::fromReturn(ret);
}
@@ -152,7 +150,7 @@
return HalResult<void>::fromReturn(ret);
}
-HalResult<sp<Aidl::IPowerHintSession>> HidlHalWrapperV1_0::createHintSession(
+HalResult<sp<hardware::power::IPowerHintSession>> HidlHalWrapperV1_0::createHintSession(
int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t) {
ALOGV("Skipped createHintSession(task num=%zu) because Power HAL not available",
threadIds.size());
@@ -166,8 +164,59 @@
// -------------------------------------------------------------------------------------------------
-HalResult<void> HidlHalWrapperV1_1::sendPowerHint(V1_0::PowerHint hintId, uint32_t data) {
- auto ret = mHandleV1_1->powerHintAsync(hintId, data);
+HalResult<void> HidlHalWrapperV1_1::sendPowerHint(V1_3::PowerHint hintId, uint32_t data) {
+ auto handle = static_cast<V1_1::IPower*>(mHandleV1_0.get());
+ auto ret = handle->powerHintAsync(static_cast<V1_0::PowerHint>(hintId), data);
+ return HalResult<void>::fromReturn(ret);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult<void> HidlHalWrapperV1_2::sendPowerHint(V1_3::PowerHint hintId, uint32_t data) {
+ auto handle = static_cast<V1_2::IPower*>(mHandleV1_0.get());
+ auto ret = handle->powerHintAsync_1_2(static_cast<V1_2::PowerHint>(hintId), data);
+ return HalResult<void>::fromReturn(ret);
+}
+
+HalResult<void> HidlHalWrapperV1_2::setBoost(Boost boost, int32_t durationMs) {
+ switch (boost) {
+ case Boost::CAMERA_SHOT:
+ return sendPowerHint(V1_3::PowerHint::CAMERA_SHOT, durationMs);
+ case Boost::CAMERA_LAUNCH:
+ return sendPowerHint(V1_3::PowerHint::CAMERA_LAUNCH, durationMs);
+ default:
+ return HidlHalWrapperV1_1::setBoost(boost, durationMs);
+ }
+}
+
+HalResult<void> HidlHalWrapperV1_2::setMode(Mode mode, bool enabled) {
+ uint32_t data = enabled ? 1 : 0;
+ switch (mode) {
+ case Mode::CAMERA_STREAMING_SECURE:
+ case Mode::CAMERA_STREAMING_LOW:
+ case Mode::CAMERA_STREAMING_MID:
+ case Mode::CAMERA_STREAMING_HIGH:
+ return sendPowerHint(V1_3::PowerHint::CAMERA_STREAMING, data);
+ case Mode::AUDIO_STREAMING_LOW_LATENCY:
+ return sendPowerHint(V1_3::PowerHint::AUDIO_LOW_LATENCY, data);
+ default:
+ return HidlHalWrapperV1_1::setMode(mode, enabled);
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult<void> HidlHalWrapperV1_3::setMode(Mode mode, bool enabled) {
+ uint32_t data = enabled ? 1 : 0;
+ if (mode == Mode::EXPENSIVE_RENDERING) {
+ return sendPowerHint(V1_3::PowerHint::EXPENSIVE_RENDERING, data);
+ }
+ return HidlHalWrapperV1_2::setMode(mode, enabled);
+}
+
+HalResult<void> HidlHalWrapperV1_3::sendPowerHint(V1_3::PowerHint hintId, uint32_t data) {
+ auto handle = static_cast<V1_3::IPower*>(mHandleV1_0.get());
+ auto ret = handle->powerHintAsync_1_3(hintId, data);
return HalResult<void>::fromReturn(ret);
}
diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp
index fcb012f..0286a81 100644
--- a/services/powermanager/benchmarks/Android.bp
+++ b/services/powermanager/benchmarks/Android.bp
@@ -38,6 +38,8 @@
"libutils",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
+ "android.hardware.power@1.2",
+ "android.hardware.power@1.3",
"android.hardware.power-V3-cpp",
],
static_libs: [
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
index 962784c..eec6801 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -31,6 +31,8 @@
"PowerHalWrapperAidlTest.cpp",
"PowerHalWrapperHidlV1_0Test.cpp",
"PowerHalWrapperHidlV1_1Test.cpp",
+ "PowerHalWrapperHidlV1_2Test.cpp",
+ "PowerHalWrapperHidlV1_3Test.cpp",
"WorkSourceTest.cpp",
],
cflags: [
@@ -47,6 +49,8 @@
"libutils",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
+ "android.hardware.power@1.2",
+ "android.hardware.power@1.3",
"android.hardware.power-V3-cpp",
],
static_libs: [
diff --git a/services/powermanager/tests/PowerHalLoaderTest.cpp b/services/powermanager/tests/PowerHalLoaderTest.cpp
index 058e1b5..e36deed 100644
--- a/services/powermanager/tests/PowerHalLoaderTest.cpp
+++ b/services/powermanager/tests/PowerHalLoaderTest.cpp
@@ -26,6 +26,8 @@
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
+using IPowerV1_2 = android::hardware::power::V1_2::IPower;
+using IPowerV1_3 = android::hardware::power::V1_3::IPower;
using IPowerAidl = android::hardware::power::IPower;
using namespace android;
@@ -52,6 +54,16 @@
return PowerHalLoader::loadHidlV1_1();
}
+template <>
+sp<IPowerV1_2> loadHal<IPowerV1_2>() {
+ return PowerHalLoader::loadHidlV1_2();
+}
+
+template <>
+sp<IPowerV1_3> loadHal<IPowerV1_3>() {
+ return PowerHalLoader::loadHidlV1_3();
+}
+
// -------------------------------------------------------------------------------------------------
template <typename T>
@@ -63,7 +75,7 @@
// -------------------------------------------------------------------------------------------------
-typedef ::testing::Types<IPowerAidl, IPowerV1_0, IPowerV1_1> PowerHalTypes;
+typedef ::testing::Types<IPowerAidl, IPowerV1_0, IPowerV1_1, IPowerV1_2, IPowerV1_3> PowerHalTypes;
TYPED_TEST_SUITE(PowerHalLoaderTest, PowerHalTypes);
TYPED_TEST(PowerHalLoaderTest, TestLoadsOnlyOnce) {
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
index b54762c..0cd2e22 100644
--- a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
@@ -87,18 +87,28 @@
}
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostUnsupported) {
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setInteractive(_)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setFeature(_, _)).Times(0);
+
auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10);
ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setBoost(Boost::ML_ACC, 10);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 10);
+ ASSERT_TRUE(result.isUnsupported());
}
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeSuccessful) {
{
InSequence seq;
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1))).Times(Exactly(1));
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LOW_POWER), Eq(0))).Times(Exactly(1));
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1)))
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(true))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LOW_POWER), Eq(false)))
.Times(Exactly(1));
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::VR_MODE), Eq(0))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(true)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::VR_MODE), Eq(false)))
+ .Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true))).Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(),
setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
@@ -131,6 +141,16 @@
}
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeIgnored) {
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setInteractive(_)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setFeature(_, _)).Times(0);
+
auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::EXPENSIVE_RENDERING, false);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::FIXED_PERFORMANCE, true);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::GAME_LOADING, false);
+ ASSERT_TRUE(result.isUnsupported());
}
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
index d30e8d2..32f84e2 100644
--- a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
@@ -31,7 +31,6 @@
using android::hardware::power::V1_0::Feature;
using android::hardware::power::V1_0::PowerHint;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
-using IPowerV1_0 = android::hardware::power::V1_0::IPower;
using namespace android;
using namespace android::power;
@@ -40,15 +39,6 @@
// -------------------------------------------------------------------------------------------------
-class MockIPowerV1_0 : public IPowerV1_0 {
-public:
- MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
- MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
- MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
- MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
- (getPlatformLowPowerStats_cb _hidl_cb), (override));
-};
-
class MockIPowerV1_1 : public IPowerV1_1 {
public:
MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
@@ -69,23 +59,22 @@
protected:
std::unique_ptr<HalWrapper> mWrapper = nullptr;
- sp<StrictMock<MockIPowerV1_0>> mMockHalV1_0 = nullptr;
- sp<StrictMock<MockIPowerV1_1>> mMockHalV1_1 = nullptr;
+ sp<StrictMock<MockIPowerV1_1>> mMockHal = nullptr;
};
// -------------------------------------------------------------------------------------------------
void PowerHalWrapperHidlV1_1Test::SetUp() {
- mMockHalV1_0 = new StrictMock<MockIPowerV1_0>();
- mMockHalV1_1 = new StrictMock<MockIPowerV1_1>();
- mWrapper = std::make_unique<HidlHalWrapperV1_1>(mMockHalV1_0, mMockHalV1_1);
+ mMockHal = new StrictMock<MockIPowerV1_1>();
+ mWrapper = std::make_unique<HidlHalWrapperV1_1>(mMockHal);
ASSERT_NE(mWrapper, nullptr);
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(0);
}
// -------------------------------------------------------------------------------------------------
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostSuccessful) {
- EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
.Times(Exactly(1));
auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
@@ -93,7 +82,7 @@
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostFailed) {
- EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
.Times(Exactly(1))
.WillRepeatedly([](PowerHint, int32_t) {
return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
@@ -104,24 +93,31 @@
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostUnsupported) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setInteractive(_)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setFeature(_, _)).Times(0);
+
auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10);
ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setBoost(Boost::ML_ACC, 10);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 10);
+ ASSERT_TRUE(result.isUnsupported());
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetMode) {
{
InSequence seq;
- EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(1)))
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(true)))
.Times(Exactly(1));
- EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LOW_POWER), Eq(0)))
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(Eq(PowerHint::LOW_POWER), Eq(false)))
.Times(Exactly(1));
- EXPECT_CALL(*mMockHalV1_1.get(),
- powerHintAsync(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1)))
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(true)))
.Times(Exactly(1));
- EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::VR_MODE), Eq(0)))
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(Eq(PowerHint::VR_MODE), Eq(false)))
.Times(Exactly(1));
- EXPECT_CALL(*mMockHalV1_0.get(), setInteractive(Eq(true))).Times(Exactly(1));
- EXPECT_CALL(*mMockHalV1_0.get(),
+ EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(),
setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
.Times(Exactly(1));
}
@@ -141,7 +137,7 @@
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeFailed) {
- EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(1)))
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(true)))
.Times(Exactly(1))
.WillRepeatedly([](PowerHint, int32_t) {
return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
@@ -152,6 +148,16 @@
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeIgnored) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setInteractive(_)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setFeature(_, _)).Times(0);
+
auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::EXPENSIVE_RENDERING, false);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::FIXED_PERFORMANCE, true);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::GAME_LOADING, false);
+ ASSERT_TRUE(result.isUnsupported());
}
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_2Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_2Test.cpp
new file mode 100644
index 0000000..cf48409
--- /dev/null
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_2Test.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PowerHalWrapperHidlV1_2Test"
+
+#include <android/hardware/power/1.2/IPower.h>
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/Mode.h>
+#include <binder/IServiceManager.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <powermanager/PowerHalWrapper.h>
+#include <utils/Log.h>
+
+using android::hardware::power::Boost;
+using android::hardware::power::Mode;
+using android::hardware::power::V1_0::Feature;
+using PowerHintV1_0 = android::hardware::power::V1_0::PowerHint;
+using PowerHintV1_2 = android::hardware::power::V1_2::PowerHint;
+
+using IPowerV1_2 = android::hardware::power::V1_2::IPower;
+
+using namespace android;
+using namespace android::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIPowerV1_2 : public IPowerV1_2 {
+public:
+ MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
+ MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHintV1_0 hint, int32_t data), (override));
+ MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+ MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+ (getPlatformLowPowerStats_cb _hidl_cb), (override));
+ MOCK_METHOD(hardware::Return<void>, powerHintAsync, (PowerHintV1_0 hint, int32_t data),
+ (override));
+ MOCK_METHOD(hardware::Return<void>, powerHintAsync_1_2, (PowerHintV1_2 hint, int32_t data),
+ (override));
+ MOCK_METHOD(hardware::Return<void>, getSubsystemLowPowerStats,
+ (getSubsystemLowPowerStats_cb _hidl_cb), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class PowerHalWrapperHidlV1_2Test : public Test {
+public:
+ void SetUp() override;
+
+protected:
+ std::unique_ptr<HalWrapper> mWrapper = nullptr;
+ sp<StrictMock<MockIPowerV1_2>> mMockHal = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+void PowerHalWrapperHidlV1_2Test::SetUp() {
+ mMockHal = new StrictMock<MockIPowerV1_2>();
+ mWrapper = std::make_unique<HidlHalWrapperV1_2>(mMockHal);
+ ASSERT_NE(mWrapper, nullptr);
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(_, _)).Times(0);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(PowerHalWrapperHidlV1_2Test, TestSetBoostSuccessful) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(Eq(PowerHintV1_2::INTERACTION), Eq(1000)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(Eq(PowerHintV1_2::CAMERA_SHOT), Eq(500)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(Eq(PowerHintV1_2::CAMERA_LAUNCH), Eq(300)))
+ .Times(Exactly(1));
+ }
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setBoost(Boost::CAMERA_SHOT, 500);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 300);
+ ASSERT_TRUE(result.isOk());
+}
+
+TEST_F(PowerHalWrapperHidlV1_2Test, TestSetBoostFailed) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(Eq(PowerHintV1_2::INTERACTION), Eq(1000)))
+ .Times(Exactly(1))
+ .WillRepeatedly([](PowerHintV1_2, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ ASSERT_TRUE(result.isFailed());
+}
+
+TEST_F(PowerHalWrapperHidlV1_2Test, TestSetBoostUnsupported) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setInteractive(_)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setFeature(_, _)).Times(0);
+
+ auto result = mWrapper->setBoost(Boost::ML_ACC, 10);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 10);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setBoost(Boost::AUDIO_LAUNCH, 10);
+ ASSERT_TRUE(result.isUnsupported());
+}
+
+TEST_F(PowerHalWrapperHidlV1_2Test, TestSetMode) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(Eq(PowerHintV1_2::LAUNCH), Eq(true)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(Eq(PowerHintV1_2::LOW_POWER), Eq(false)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_2(Eq(PowerHintV1_2::SUSTAINED_PERFORMANCE), Eq(true)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(Eq(PowerHintV1_2::VR_MODE), Eq(false)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true))).Times(Exactly(true));
+ EXPECT_CALL(*mMockHal.get(),
+ setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_2(Eq(PowerHintV1_2::CAMERA_STREAMING), Eq(true)))
+ .Times(Exactly(2));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_2(Eq(PowerHintV1_2::CAMERA_STREAMING), Eq(false)))
+ .Times(Exactly(2));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_2(Eq(PowerHintV1_2::AUDIO_LOW_LATENCY), Eq(true)))
+ .Times(Exactly(1));
+ }
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::LOW_POWER, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::VR, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::INTERACTIVE, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_SECURE, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_LOW, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_MID, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::AUDIO_STREAMING_LOW_LATENCY, true);
+ ASSERT_TRUE(result.isOk());
+}
+
+TEST_F(PowerHalWrapperHidlV1_2Test, TestSetModeFailed) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(Eq(PowerHintV1_2::LAUNCH), Eq(1)))
+ .Times(Exactly(1))
+ .WillRepeatedly([](PowerHintV1_2, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, 1);
+ ASSERT_TRUE(result.isFailed());
+}
+
+TEST_F(PowerHalWrapperHidlV1_2Test, TestSetModeIgnored) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setInteractive(_)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setFeature(_, _)).Times(0);
+
+ auto result = mWrapper->setMode(Mode::EXPENSIVE_RENDERING, true);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, true);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::FIXED_PERFORMANCE, true);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::GAME_LOADING, false);
+ ASSERT_TRUE(result.isUnsupported());
+}
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_3Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_3Test.cpp
new file mode 100644
index 0000000..2c48537
--- /dev/null
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_3Test.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PowerHalWrapperHidlV1_3Test"
+
+#include <android/hardware/power/1.3/IPower.h>
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/Mode.h>
+#include <binder/IServiceManager.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <powermanager/PowerHalWrapper.h>
+#include <utils/Log.h>
+
+using android::hardware::power::Boost;
+using android::hardware::power::Mode;
+using android::hardware::power::V1_0::Feature;
+using PowerHintV1_0 = android::hardware::power::V1_0::PowerHint;
+using PowerHintV1_2 = android::hardware::power::V1_2::PowerHint;
+using PowerHintV1_3 = android::hardware::power::V1_3::PowerHint;
+
+using IPowerV1_3 = android::hardware::power::V1_3::IPower;
+
+using namespace android;
+using namespace android::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIPowerV1_3 : public IPowerV1_3 {
+public:
+ MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
+ MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHintV1_0 hint, int32_t data), (override));
+ MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+ MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+ (getPlatformLowPowerStats_cb _hidl_cb), (override));
+ MOCK_METHOD(hardware::Return<void>, powerHintAsync, (PowerHintV1_0 hint, int32_t data),
+ (override));
+ MOCK_METHOD(hardware::Return<void>, powerHintAsync_1_2, (PowerHintV1_2 hint, int32_t data),
+ (override));
+ MOCK_METHOD(hardware::Return<void>, powerHintAsync_1_3, (PowerHintV1_3 hint, int32_t data),
+ (override));
+
+ MOCK_METHOD(hardware::Return<void>, getSubsystemLowPowerStats,
+ (getSubsystemLowPowerStats_cb _hidl_cb), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class PowerHalWrapperHidlV1_3Test : public Test {
+public:
+ void SetUp() override;
+
+protected:
+ std::unique_ptr<HalWrapper> mWrapper = nullptr;
+ sp<StrictMock<MockIPowerV1_3>> mMockHal = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+void PowerHalWrapperHidlV1_3Test::SetUp() {
+ mMockHal = new StrictMock<MockIPowerV1_3>();
+ mWrapper = std::make_unique<HidlHalWrapperV1_3>(mMockHal);
+ ASSERT_NE(mWrapper, nullptr);
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_2(_, _)).Times(0);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(PowerHalWrapperHidlV1_3Test, TestSetBoostSuccessful) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(Eq(PowerHintV1_3::INTERACTION), Eq(1000)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(Eq(PowerHintV1_3::CAMERA_SHOT), Eq(500)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(Eq(PowerHintV1_3::CAMERA_LAUNCH), Eq(300)))
+ .Times(Exactly(1));
+ }
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setBoost(Boost::CAMERA_SHOT, 500);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 300);
+ ASSERT_TRUE(result.isOk());
+}
+
+TEST_F(PowerHalWrapperHidlV1_3Test, TestSetBoostFailed) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(Eq(PowerHintV1_3::INTERACTION), Eq(1000)))
+ .Times(Exactly(1))
+ .WillRepeatedly([](PowerHintV1_3, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ ASSERT_TRUE(result.isFailed());
+}
+
+TEST_F(PowerHalWrapperHidlV1_3Test, TestSetBoostUnsupported) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setInteractive(_)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setFeature(_, _)).Times(0);
+
+ auto result = mWrapper->setBoost(Boost::ML_ACC, 10);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 10);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setBoost(Boost::AUDIO_LAUNCH, 10);
+ ASSERT_TRUE(result.isUnsupported());
+}
+
+TEST_F(PowerHalWrapperHidlV1_3Test, TestSetMode) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(Eq(PowerHintV1_3::LAUNCH), Eq(true)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(Eq(PowerHintV1_3::LOW_POWER), Eq(false)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_3(Eq(PowerHintV1_3::SUSTAINED_PERFORMANCE), Eq(true)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(Eq(PowerHintV1_3::VR_MODE), Eq(false)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true))).Times(Exactly(true));
+ EXPECT_CALL(*mMockHal.get(),
+ setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_3(Eq(PowerHintV1_3::CAMERA_STREAMING), Eq(true)))
+ .Times(Exactly(2));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_3(Eq(PowerHintV1_3::CAMERA_STREAMING), Eq(false)))
+ .Times(Exactly(2));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_3(Eq(PowerHintV1_3::AUDIO_LOW_LATENCY), Eq(true)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(),
+ powerHintAsync_1_3(Eq(PowerHintV1_3::EXPENSIVE_RENDERING), Eq(false)))
+ .Times(Exactly(1));
+ }
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::LOW_POWER, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::VR, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::INTERACTIVE, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_SECURE, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_LOW, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_MID, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, false);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::AUDIO_STREAMING_LOW_LATENCY, true);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->setMode(Mode::EXPENSIVE_RENDERING, false);
+ ASSERT_TRUE(result.isOk());
+}
+
+TEST_F(PowerHalWrapperHidlV1_3Test, TestSetModeFailed) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(Eq(PowerHintV1_3::LAUNCH), Eq(1)))
+ .Times(Exactly(1))
+ .WillRepeatedly([](PowerHintV1_3, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, 1);
+ ASSERT_TRUE(result.isFailed());
+}
+
+TEST_F(PowerHalWrapperHidlV1_3Test, TestSetModeIgnored) {
+ EXPECT_CALL(*mMockHal.get(), powerHintAsync_1_3(_, _)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setInteractive(_)).Times(0);
+ EXPECT_CALL(*mMockHal.get(), setFeature(_, _)).Times(0);
+
+ auto result = mWrapper->setMode(Mode::GAME, true);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, true);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::FIXED_PERFORMANCE, true);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->setMode(Mode::GAME_LOADING, false);
+ ASSERT_TRUE(result.isUnsupported());
+}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index b911ae7..8a76d7c 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -84,7 +84,6 @@
"libserviceutils",
"libshaders",
"libtonemap",
- "libtrace_proto",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -189,11 +188,11 @@
"StartPropertySetThread.cpp",
"SurfaceFlinger.cpp",
"SurfaceFlingerDefaultFactory.cpp",
- "SurfaceInterceptor.cpp",
"Tracing/LayerTracing.cpp",
"Tracing/TransactionTracing.cpp",
"Tracing/TransactionProtoParser.cpp",
"TransactionCallbackInvoker.cpp",
+ "TransactionHandler.cpp",
"TunnelModeEnabledReporter.cpp",
],
}
@@ -224,7 +223,6 @@
],
static_libs: [
"libserviceutils",
- "libtrace_proto",
],
}
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 3685bb4..30b8759 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -81,17 +81,9 @@
gui::CreateSurfaceResult* outResult) {
// We rely on createLayer to check permissions.
sp<IBinder> handle;
- int32_t layerId;
- uint32_t transformHint;
LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), name.c_str(),
static_cast<uint32_t>(flags), std::move(metadata));
- const status_t status =
- mFlinger->createLayer(args, &handle, parent, &layerId, nullptr, &transformHint);
- if (status == NO_ERROR) {
- outResult->handle = handle;
- outResult->layerId = layerId;
- outResult->transformHint = static_cast<int32_t>(transformHint);
- }
+ const status_t status = mFlinger->createLayer(args, parent, *outResult);
return binderStatusFromStatusT(status);
}
@@ -134,31 +126,21 @@
}
binder::Status Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle,
- gui::MirrorSurfaceResult* outResult) {
+ gui::CreateSurfaceResult* outResult) {
sp<IBinder> handle;
- int32_t layerId;
LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), "MirrorRoot",
0 /* flags */, gui::LayerMetadata());
- status_t status = mFlinger->mirrorLayer(args, mirrorFromHandle, &handle, &layerId);
- if (status == NO_ERROR) {
- outResult->handle = handle;
- outResult->layerId = layerId;
- }
+ status_t status = mFlinger->mirrorLayer(args, mirrorFromHandle, *outResult);
return binderStatusFromStatusT(status);
}
-binder::Status Client::mirrorDisplay(int64_t displayId, gui::MirrorSurfaceResult* outResult) {
+binder::Status Client::mirrorDisplay(int64_t displayId, gui::CreateSurfaceResult* outResult) {
sp<IBinder> handle;
- int32_t layerId;
LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this),
"MirrorRoot-" + std::to_string(displayId), 0 /* flags */,
gui::LayerMetadata());
std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
- status_t status = mFlinger->mirrorDisplay(*id, args, &handle, &layerId);
- if (status == NO_ERROR) {
- outResult->handle = handle;
- outResult->layerId = layerId;
- }
+ status_t status = mFlinger->mirrorDisplay(*id, args, *outResult);
return binderStatusFromStatusT(status);
}
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 4e59dfd..02079a3 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -57,9 +57,9 @@
gui::FrameStats* outStats) override;
binder::Status mirrorSurface(const sp<IBinder>& mirrorFromHandle,
- gui::MirrorSurfaceResult* outResult) override;
+ gui::CreateSurfaceResult* outResult) override;
- binder::Status mirrorDisplay(int64_t displayId, gui::MirrorSurfaceResult* outResult) override;
+ binder::Status mirrorDisplay(int64_t displayId, gui::CreateSurfaceResult* outResult) override;
// constant
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index cf932a8..b01932e 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -22,6 +22,7 @@
#include <cinttypes>
#include <android-base/stringprintf.h>
+#include <gui/TraceUtils.h>
#include <renderengine/impl/ExternalTexture.h>
#include "ClientCache.h"
@@ -36,12 +37,12 @@
ClientCacheBuffer** outClientCacheBuffer) {
auto& [processToken, id] = cacheId;
if (processToken == nullptr) {
- ALOGE("failed to get buffer, invalid (nullptr) process token");
+ ALOGE_AND_TRACE("ClientCache::getBuffer - invalid (nullptr) process token");
return false;
}
auto it = mBuffers.find(processToken);
if (it == mBuffers.end()) {
- ALOGE("failed to get buffer, invalid process token");
+ ALOGE_AND_TRACE("ClientCache::getBuffer - invalid process token");
return false;
}
@@ -49,7 +50,7 @@
auto bufItr = processBuffers.find(id);
if (bufItr == processBuffers.end()) {
- ALOGV("failed to get buffer, invalid buffer id");
+ ALOGE_AND_TRACE("ClientCache::getBuffer - invalid buffer id");
return false;
}
@@ -61,12 +62,12 @@
bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
auto& [processToken, id] = cacheId;
if (processToken == nullptr) {
- ALOGE("failed to cache buffer: invalid process token");
+ ALOGE_AND_TRACE("ClientCache::add - invalid (nullptr) process token");
return false;
}
if (!buffer) {
- ALOGE("failed to cache buffer: invalid buffer");
+ ALOGE_AND_TRACE("ClientCache::add - invalid (nullptr) buffer");
return false;
}
@@ -79,7 +80,7 @@
if (it == mBuffers.end()) {
token = processToken.promote();
if (!token) {
- ALOGE("failed to cache buffer: invalid token");
+ ALOGE_AND_TRACE("ClientCache::add - invalid token");
return false;
}
@@ -87,7 +88,7 @@
if (token->localBinder() == nullptr) {
status_t err = token->linkToDeath(mDeathRecipient);
if (err != NO_ERROR) {
- ALOGE("failed to cache buffer: could not link to death");
+ ALOGE_AND_TRACE("ClientCache::add - could not link to death");
return false;
}
}
@@ -102,7 +103,7 @@
auto& processBuffers = it->second.second;
if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
- ALOGE("failed to cache buffer: cache is full");
+ ALOGE_AND_TRACE("ClientCache::add - cache is full");
return false;
}
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index b5d2ad0..0ae8bf9 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -42,7 +42,6 @@
"libmath",
"librenderengine",
"libtonemap",
- "libtrace_proto",
"libaidlcommonsupport",
"libprocessgroup",
"libcgrouprc",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index 3faa068..6832ae1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -18,9 +18,10 @@
#include <TimeStats/TimeStats.h>
#include <utils/Timers.h>
-
#include <memory>
+#include "Feature.h"
+
namespace android {
class HWComposer;
@@ -72,6 +73,8 @@
// TODO(b/121291683): These will become private/internal
virtual void preComposition(CompositionRefreshArgs&) = 0;
+ virtual FeatureFlags getFeatureFlags() const = 0;
+
// Debugging
virtual void dump(std::string&) const = 0;
};
diff --git a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl b/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h
similarity index 64%
copy from libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
copy to services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h
index 9fac3e8..ee8000a 100644
--- a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,17 @@
* limitations under the License.
*/
-package android.gui;
+#pragma once
-/** @hide */
-parcelable MirrorSurfaceResult {
- IBinder handle;
- int layerId;
-}
+#include <ftl/flags.h>
+#include <cstdint>
+
+namespace android::compositionengine {
+
+enum class Feature : int32_t {
+ kSnapshotLayerMetadata = 1 << 0,
+};
+
+using FeatureFlags = ftl::Flags<Feature>;
+
+} // namespace android::compositionengine
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index a738da0..fe8cad5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -39,6 +39,10 @@
class Fence;
+namespace gui {
+struct LayerMetadata;
+}
+
namespace compositionengine {
struct LayerFECompositionState;
@@ -144,6 +148,8 @@
// Whether the layer should be rendered with rounded corners.
virtual bool hasRoundedCorners() const = 0;
virtual void setWasClientComposed(const sp<Fence>&) {}
+ virtual const gui::LayerMetadata* getMetadata() const = 0;
+ virtual const gui::LayerMetadata* getRelativeMetadata() const = 0;
};
// TODO(b/121291683): Specialize std::hash<> for sp<T> so these and others can
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 0907926..dd4dbe9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -48,6 +48,8 @@
void preComposition(CompositionRefreshArgs&) override;
+ FeatureFlags getFeatureFlags() const override;
+
// Debugging
void dump(std::string&) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index f953d0b..a48cc6f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -53,6 +53,8 @@
MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&));
+ MOCK_CONST_METHOD0(getFeatureFlags, FeatureFlags());
+
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index be0dbce..14922a4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -53,6 +53,8 @@
MOCK_CONST_METHOD0(getDebugName, const char*());
MOCK_CONST_METHOD0(getSequence, int32_t());
MOCK_CONST_METHOD0(hasRoundedCorners, bool());
+ MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*());
+ MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 855507e..a4e1fff 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -140,6 +140,10 @@
mNeedsAnotherUpdate = needsAnotherUpdate;
}
+FeatureFlags CompositionEngine::getFeatureFlags() const {
+ return {};
+}
+
void CompositionEngine::dump(std::string&) const {
// The base class has no state to dump, but derived classes might.
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 59e34ed..758b346 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -70,6 +70,7 @@
MOCK_METHOD1(disconnectDisplay, void(HalDisplayId));
MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&));
MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(HalDisplayId));
+ MOCK_METHOD(nsecs_t, getPresentTimestamp, (PhysicalDisplayId), (const, override));
MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(HalDisplayId, HWC2::Layer*));
MOCK_METHOD3(setOutputBuffer,
status_t(HalVirtualDisplayId, const sp<Fence>&, const sp<GraphicBuffer>&));
diff --git a/services/surfaceflinger/Display/DisplayMap.h b/services/surfaceflinger/Display/DisplayMap.h
index baf0da9..0d59706 100644
--- a/services/surfaceflinger/Display/DisplayMap.h
+++ b/services/surfaceflinger/Display/DisplayMap.h
@@ -17,6 +17,7 @@
#pragma once
#include <ftl/small_map.h>
+#include <ftl/small_vector.h>
namespace android::display {
@@ -28,4 +29,7 @@
template <typename Key, typename Value>
using PhysicalDisplayMap = ftl::SmallMap<Key, Value, 3>;
+template <typename T>
+using PhysicalDisplayVector = ftl::SmallVector<T, 3>;
+
} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplaySnapshot.cpp b/services/surfaceflinger/Display/DisplaySnapshot.cpp
index b4f104a..0c7a58e 100644
--- a/services/surfaceflinger/Display/DisplaySnapshot.cpp
+++ b/services/surfaceflinger/Display/DisplaySnapshot.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
+#include <algorithm>
#include <functional>
#include <utility>
#include <ftl/algorithm.h>
#include <ftl/enum.h>
+#include <ui/DebugUtils.h>
#include "DisplaySnapshot.h"
@@ -26,11 +28,12 @@
DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId,
ui::DisplayConnectionType connectionType,
- DisplayModes&& displayModes,
+ DisplayModes&& displayModes, ui::ColorModes&& colorModes,
std::optional<DeviceProductInfo>&& deviceProductInfo)
: mDisplayId(displayId),
mConnectionType(connectionType),
mDisplayModes(std::move(displayModes)),
+ mColorModes(std::move(colorModes)),
mDeviceProductInfo(std::move(deviceProductInfo)) {}
std::optional<DisplayModeId> DisplaySnapshot::translateModeId(hal::HWConfigId hwcId) const {
@@ -41,18 +44,35 @@
.transform(&ftl::to_key<DisplayModes>);
}
-void DisplaySnapshot::dump(std::string& out) const {
- using namespace std::string_literals;
+ui::ColorModes DisplaySnapshot::filterColorModes(bool supportsWideColor) const {
+ ui::ColorModes modes = mColorModes;
- out += " connectionType="s;
- out += ftl::enum_string(mConnectionType);
-
- out += "\n deviceProductInfo="s;
- if (mDeviceProductInfo) {
- mDeviceProductInfo->dump(out);
- } else {
- out += "{}"s;
+ // If the display is internal and the configuration claims it's not wide color capable, filter
+ // out all wide color modes. The typical reason why this happens is that the hardware is not
+ // good enough to support GPU composition of wide color, and thus the OEMs choose to disable
+ // this capability.
+ if (mConnectionType == ui::DisplayConnectionType::Internal && !supportsWideColor) {
+ const auto it = std::remove_if(modes.begin(), modes.end(), ui::isWideColorMode);
+ modes.erase(it, modes.end());
}
+
+ return modes;
+}
+
+void DisplaySnapshot::dump(utils::Dumper& dumper) const {
+ using namespace std::string_view_literals;
+
+ dumper.dump("connectionType"sv, ftl::enum_string(mConnectionType));
+
+ dumper.dump("colorModes"sv);
+ {
+ utils::Dumper::Indent indent(dumper);
+ for (const auto mode : mColorModes) {
+ dumper.dump({}, decodeColorMode(mode));
+ }
+ }
+
+ dumper.dump("deviceProductInfo"sv, mDeviceProductInfo);
}
} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplaySnapshot.h b/services/surfaceflinger/Display/DisplaySnapshot.h
index 0279220..23471f5 100644
--- a/services/surfaceflinger/Display/DisplaySnapshot.h
+++ b/services/surfaceflinger/Display/DisplaySnapshot.h
@@ -17,19 +17,20 @@
#pragma once
#include <optional>
-#include <string>
+#include <ui/ColorMode.h>
#include <ui/DisplayId.h>
#include <ui/StaticDisplayInfo.h>
-#include "../DisplayHardware/DisplayMode.h"
+#include "DisplayHardware/DisplayMode.h"
+#include "Utils/Dumper.h"
namespace android::display {
// Immutable state of a physical display, captured on hotplug.
class DisplaySnapshot {
public:
- DisplaySnapshot(PhysicalDisplayId, ui::DisplayConnectionType, DisplayModes&&,
+ DisplaySnapshot(PhysicalDisplayId, ui::DisplayConnectionType, DisplayModes&&, ui::ColorModes&&,
std::optional<DeviceProductInfo>&&);
DisplaySnapshot(const DisplaySnapshot&) = delete;
@@ -41,9 +42,12 @@
std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const;
const auto& displayModes() const { return mDisplayModes; }
+ const auto& colorModes() const { return mColorModes; }
const auto& deviceProductInfo() const { return mDeviceProductInfo; }
- void dump(std::string&) const;
+ ui::ColorModes filterColorModes(bool supportsWideColor) const;
+
+ void dump(utils::Dumper&) const;
private:
const PhysicalDisplayId mDisplayId;
@@ -51,6 +55,7 @@
// Effectively const except in move constructor.
DisplayModes mDisplayModes;
+ ui::ColorModes mColorModes;
std::optional<DeviceProductInfo> mDeviceProductInfo;
};
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a25296c..c63d57f 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -216,7 +216,6 @@
to_string(getId()).c_str());
return BAD_VALUE;
}
- mNumModeSwitchesInPolicy++;
mUpcomingActiveMode = info;
ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
@@ -238,16 +237,6 @@
return refreshRateConfigs().getActiveModePtr()->getVsyncPeriod();
}
-nsecs_t DisplayDevice::getRefreshTimestamp() const {
- const nsecs_t now = systemTime(CLOCK_MONOTONIC);
- const auto vsyncPeriodNanos = getVsyncPeriodFromHWC();
- return now - ((now - mLastHwVsync) % vsyncPeriodNanos);
-}
-
-void DisplayDevice::onVsync(nsecs_t timestamp) {
- mLastHwVsync = timestamp;
-}
-
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
return mCompositionDisplay->getState().dataspace;
}
@@ -338,17 +327,16 @@
return name + ", \""s + mDisplayName + "\")"s;
}
-void DisplayDevice::dump(std::string& result) const {
- using namespace std::string_literals;
+void DisplayDevice::dump(utils::Dumper& dumper) const {
+ using namespace std::string_view_literals;
- result += getDebugName();
+ dumper.dump({}, getDebugName());
- result += "\n powerMode="s;
- result += mPowerMode.has_value() ? to_string(mPowerMode.value()) : "OFF(reset)";
- result += '\n';
+ utils::Dumper::Indent indent(dumper);
+ dumper.dump("powerMode"sv, mPowerMode);
if (mRefreshRateConfigs) {
- mRefreshRateConfigs->dump(result);
+ mRefreshRateConfigs->dump(dumper);
}
}
@@ -509,27 +497,6 @@
mDesiredActiveModeChanged = false;
}
-status_t DisplayDevice::setRefreshRatePolicy(
- const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
- const auto oldPolicy = mRefreshRateConfigs->getCurrentPolicy();
- const status_t setPolicyResult = overridePolicy
- ? mRefreshRateConfigs->setOverridePolicy(policy)
- : mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
-
- if (setPolicyResult == OK) {
- const int numModeChanges = mNumModeSwitchesInPolicy.exchange(0);
-
- ALOGI("Display %s policy changed\n"
- "Previous: {%s}\n"
- "Current: {%s}\n"
- "%d mode changes were performed under the previous policy",
- to_string(getId()).c_str(), oldPolicy.toString().c_str(),
- policy ? policy->toString().c_str() : "null", numModeChanges);
- }
-
- return setPolicyResult;
-}
-
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 0f52aff..06a812b 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -47,6 +47,7 @@
#include "Scheduler/RefreshRateConfigs.h"
#include "ThreadContext.h"
#include "TracedOrdinal.h"
+#include "Utils/Dumper.h"
namespace android {
@@ -233,13 +234,7 @@
bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
void animateRefreshRateOverlay();
- void onVsync(nsecs_t timestamp);
nsecs_t getVsyncPeriodFromHWC() const;
- nsecs_t getRefreshTimestamp() const;
-
- status_t setRefreshRatePolicy(
- const std::optional<scheduler::RefreshRateConfigs::Policy>& policy,
- bool overridePolicy);
// release HWC resources (if any) for removable displays
void disconnect();
@@ -248,7 +243,7 @@
* Debugging
*/
std::string getDebugName() const;
- void dump(std::string& result) const;
+ void dump(utils::Dumper&) const;
private:
const sp<SurfaceFlinger> mFlinger;
@@ -273,8 +268,6 @@
std::optional<float> mStagedBrightness;
float mBrightness = -1.f;
- std::atomic<nsecs_t> mLastHwVsync = 0;
-
// TODO(b/182939859): Remove special cases for primary display.
const bool mIsPrimary;
@@ -290,8 +283,6 @@
TracedOrdinal<bool> mDesiredActiveModeChanged
GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
-
- std::atomic_int mNumModeSwitchesInPolicy = 0;
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index a4a89ea..0e41962 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -265,17 +265,21 @@
}
std::string str;
+ // Use other thread to read pipe to prevent
+ // pipe is full, making HWC be blocked in writing.
+ std::thread t([&]() {
+ base::ReadFdToString(pipefds[0], &str);
+ });
const auto status = mAidlComposer->dump(pipefds[1], /*args*/ nullptr, /*numArgs*/ 0);
// Close the write-end of the pipe to make sure that when reading from the
// read-end we will get eof instead of blocking forever
close(pipefds[1]);
- if (status == STATUS_OK) {
- base::ReadFdToString(pipefds[0], &str);
- } else {
+ if (status != STATUS_OK) {
ALOGE("dumpDebugInfo: dump failed: %d", status);
}
+ t.join();
close(pipefds[0]);
return str;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 91ded86..4971d19 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -71,7 +71,7 @@
struct ComposerCallback {
virtual void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) = 0;
virtual void onComposerHalRefresh(hal::HWDisplayId) = 0;
- virtual void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp,
+ virtual void onComposerHalVsync(hal::HWDisplayId, nsecs_t timestamp,
std::optional<hal::VsyncPeriodNanos>) = 0;
virtual void onComposerHalVsyncPeriodTimingChanged(hal::HWDisplayId,
const hal::VsyncPeriodChangeTimeline&) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index bf1d9ea..168e2dd 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -144,7 +144,7 @@
return mUpdateDeviceProductInfoOnHotplugReconnect;
}
-bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) {
+bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, nsecs_t timestamp) {
const auto displayId = toPhysicalDisplayId(hwcDisplayId);
if (!displayId) {
LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
@@ -160,13 +160,13 @@
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
- if (timestamp == displayData.lastHwVsync) {
+ if (timestamp == displayData.lastPresentTimestamp) {
ALOGW("Ignoring duplicate VSYNC event from HWC for display %s (t=%" PRId64 ")",
to_string(*displayId).c_str(), timestamp);
return false;
}
- displayData.lastHwVsync = timestamp;
+ displayData.lastPresentTimestamp = timestamp;
}
const auto tag = "HW_VSYNC_" + to_string(*displayId);
@@ -485,6 +485,11 @@
return mDisplayData.at(displayId).lastPresentFence;
}
+nsecs_t HWComposer::getPresentTimestamp(PhysicalDisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, 0);
+ return mDisplayData.at(displayId).lastPresentTimestamp;
+}
+
sp<Fence> HWComposer::getLayerReleaseFence(HalDisplayId displayId, HWC2::Layer* layer) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
const auto& displayFences = mDisplayData.at(displayId).releaseFences;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0b141ba..8235b88 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -161,8 +161,9 @@
// reset state when a display is disconnected
virtual void disconnectDisplay(HalDisplayId) = 0;
- // get the present fence received from the last call to present.
+ // Get the present fence/timestamp received from the last call to present.
virtual sp<Fence> getPresentFence(HalDisplayId) const = 0;
+ virtual nsecs_t getPresentTimestamp(PhysicalDisplayId) const = 0;
// Get last release fence for the given layer
virtual sp<Fence> getLayerReleaseFence(HalDisplayId, HWC2::Layer*) const = 0;
@@ -218,7 +219,7 @@
// TODO(b/157555476): Remove when the framework has proper support for headless mode
virtual bool updatesDeviceProductInfoOnHotplugReconnect() const = 0;
- virtual bool onVsync(hal::HWDisplayId, int64_t timestamp) = 0;
+ virtual bool onVsync(hal::HWDisplayId, nsecs_t timestamp) = 0;
virtual void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) = 0;
virtual bool isConnected(PhysicalDisplayId) const = 0;
@@ -347,8 +348,9 @@
// reset state when a display is disconnected
void disconnectDisplay(HalDisplayId) override;
- // get the present fence received from the last call to present.
+ // Get the present fence/timestamp received from the last call to present.
sp<Fence> getPresentFence(HalDisplayId) const override;
+ nsecs_t getPresentTimestamp(PhysicalDisplayId) const override;
// Get last release fence for the given layer
sp<Fence> getLayerReleaseFence(HalDisplayId, HWC2::Layer*) const override;
@@ -394,7 +396,7 @@
bool updatesDeviceProductInfoOnHotplugReconnect() const override;
- bool onVsync(hal::HWDisplayId, int64_t timestamp) override;
+ bool onVsync(hal::HWDisplayId, nsecs_t timestamp) override;
void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) override;
bool isConnected(PhysicalDisplayId) const override;
@@ -463,7 +465,10 @@
struct DisplayData {
std::unique_ptr<HWC2::Display> hwcDisplay;
+
sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
+ nsecs_t lastPresentTimestamp = 0;
+
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
bool validateWasSkipped;
@@ -473,8 +478,6 @@
std::mutex vsyncEnabledLock;
hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE;
-
- nsecs_t lastHwVsync = 0;
};
std::optional<DisplayIdentificationInfo> onHotplugConnect(hal::HWDisplayId);
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index 4737034..33a7bca 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -177,6 +177,9 @@
return to_string(static_cast<hardware::graphics::composer::hal::V2_4::Error>(error));
}
+// For utils::Dumper ADL.
+namespace hardware::graphics::composer::V2_2 {
+
inline std::string to_string(hardware::graphics::composer::hal::PowerMode mode) {
switch (mode) {
case hardware::graphics::composer::hal::PowerMode::OFF:
@@ -194,6 +197,8 @@
}
}
+} // namespace hardware::graphics::composer::V2_2
+
inline std::string to_string(hardware::graphics::composer::hal::Vsync vsync) {
switch (vsync) {
case hardware::graphics::composer::hal::Vsync::ENABLE:
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index c73a75c..cd1ba70 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -892,6 +892,10 @@
mJankType = JankType::Unknown;
deadlineDelta = 0;
deltaToVsync = 0;
+ if (mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
+ mSurfaceFlingerActuals.presentTime = mSurfaceFlingerActuals.endTime;
+ }
+
return;
}
@@ -1168,22 +1172,50 @@
static_cast<float>(totalPresentToPresentWalls);
}
+std::optional<size_t> FrameTimeline::getFirstSignalFenceIndex() const {
+ for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
+ const auto& [fence, _] = mPendingPresentFences[i];
+ if (fence && fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
+ return i;
+ }
+ }
+
+ return {};
+}
+
void FrameTimeline::flushPendingPresentFences() {
+ const auto firstSignaledFence = getFirstSignalFenceIndex();
+ if (!firstSignaledFence.has_value()) {
+ return;
+ }
+
// Perfetto is using boottime clock to void drifts when the device goes
// to suspend.
const auto monoBootOffset = mUseBootTimeClock
? (systemTime(SYSTEM_TIME_BOOTTIME) - systemTime(SYSTEM_TIME_MONOTONIC))
: 0;
+ // Present fences are expected to be signaled in order. Mark all the previous
+ // pending fences as errors.
+ for (size_t i = 0; i < firstSignaledFence.value(); i++) {
+ const auto& pendingPresentFence = *mPendingPresentFences.begin();
+ const nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
+ auto& displayFrame = pendingPresentFence.second;
+ displayFrame->onPresent(signalTime, mPreviousPresentTime);
+ displayFrame->trace(mSurfaceFlingerPid, monoBootOffset);
+ mPendingPresentFences.erase(mPendingPresentFences.begin());
+ }
+
for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
const auto& pendingPresentFence = mPendingPresentFences[i];
nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
if (pendingPresentFence.first && pendingPresentFence.first->isValid()) {
signalTime = pendingPresentFence.first->getSignalTime();
if (signalTime == Fence::SIGNAL_TIME_PENDING) {
- continue;
+ break;
}
}
+
auto& displayFrame = pendingPresentFence.second;
displayFrame->onPresent(signalTime, mPreviousPresentTime);
displayFrame->trace(mSurfaceFlingerPid, monoBootOffset);
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index a2305af..31074b1 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -474,6 +474,7 @@
friend class android::frametimeline::FrameTimelineTest;
void flushPendingPresentFences() REQUIRES(mMutex);
+ std::optional<size_t> getFirstSignalFenceIndex() const REQUIRES(mMutex);
void finalizeCurrentDisplayFrame() REQUIRES(mMutex);
void dumpAll(std::string& result);
void dumpJank(std::string& result);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 13437a4..9bb9305 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3633,7 +3633,7 @@
}
if (s.what & layer_state_t::eAlphaChanged) {
- if (mDrawingState.color.a != s.alpha) {
+ if (mDrawingState.color.a != s.color.a) {
ALOGV("%s: false [eAlphaChanged changed]", __func__);
return false;
}
@@ -3677,9 +3677,9 @@
}
}
- if (s.what & layer_state_t::eTransformChanged) {
- if (mDrawingState.bufferTransform != s.transform) {
- ALOGV("%s: false [eTransformChanged changed]", __func__);
+ if (s.what & layer_state_t::eBufferTransformChanged) {
+ if (mDrawingState.bufferTransform != s.bufferTransform) {
+ ALOGV("%s: false [eBufferTransformChanged changed]", __func__);
return false;
}
}
@@ -3918,9 +3918,14 @@
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
} else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId());
displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
- // The HWC doesn't support present fences, so use the refresh
- // timestamp instead.
- const nsecs_t actualPresentTime = display->getRefreshTimestamp();
+ // The HWC doesn't support present fences, so use the present timestamp instead.
+ const nsecs_t presentTimestamp =
+ mFlinger->getHwComposer().getPresentTimestamp(*displayId);
+
+ const nsecs_t now = systemTime(CLOCK_MONOTONIC);
+ const nsecs_t vsyncPeriod = display->getVsyncPeriodFromHWC();
+ const nsecs_t actualPresentTime = now - ((now - presentTimestamp) % vsyncPeriod);
+
mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
refreshRate, renderRate, vote, gameMode);
mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(),
@@ -4172,15 +4177,12 @@
}
bool Layer::setColor(const half3& color) {
- if (mDrawingState.color.r == color.r && mDrawingState.color.g == color.g &&
- mDrawingState.color.b == color.b) {
+ if (mDrawingState.color.rgb == color) {
return false;
}
mDrawingState.sequence++;
- mDrawingState.color.r = color.r;
- mDrawingState.color.g = color.g;
- mDrawingState.color.b = color.b;
+ mDrawingState.color.rgb = color;
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
@@ -4241,6 +4243,38 @@
preparePerFrameCompositionState();
}
+void Layer::updateMetadataSnapshot(const LayerMetadata& parentMetadata) {
+ mSnapshot->layerMetadata = parentMetadata;
+ mSnapshot->layerMetadata.merge(mDrawingState.metadata);
+ for (const sp<Layer>& child : mDrawingChildren) {
+ child->updateMetadataSnapshot(mSnapshot->layerMetadata);
+ }
+}
+
+void Layer::updateRelativeMetadataSnapshot(const LayerMetadata& relativeLayerMetadata,
+ std::unordered_set<Layer*>& visited) {
+ if (visited.find(this) != visited.end()) {
+ ALOGW("Cycle containing layer %s detected in z-order relatives", getDebugName());
+ return;
+ }
+ visited.insert(this);
+
+ mSnapshot->relativeLayerMetadata = relativeLayerMetadata;
+
+ if (mDrawingState.zOrderRelatives.empty()) {
+ return;
+ }
+ LayerMetadata childRelativeLayerMetadata = mSnapshot->relativeLayerMetadata;
+ childRelativeLayerMetadata.merge(mSnapshot->layerMetadata);
+ for (wp<Layer> weakRelative : mDrawingState.zOrderRelatives) {
+ sp<Layer> relative = weakRelative.promote();
+ if (!relative) {
+ continue;
+ }
+ relative->updateRelativeMetadataSnapshot(childRelativeLayerMetadata, visited);
+ }
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4079d16..8ace812 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -77,10 +77,6 @@
class LayerDebugInfo;
}
-namespace impl {
-class SurfaceInterceptor;
-}
-
namespace frametimeline {
class SurfaceFrame;
} // namespace frametimeline
@@ -166,6 +162,8 @@
ui::Transform transform;
Rect bufferSize;
std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ LayerMetadata layerMetadata;
+ LayerMetadata relativeLayerMetadata;
};
using FrameRate = scheduler::LayerInfo::FrameRate;
@@ -611,6 +609,12 @@
mClearClientCompositionFenceOnLayerDisplayed = false;
}
+ const LayerMetadata* getMetadata() const override { return &mSnapshot->layerMetadata; }
+
+ const LayerMetadata* getRelativeMetadata() const override {
+ return &mSnapshot->relativeLayerMetadata;
+ }
+
const char* getDebugName() const override;
bool setShadowRadius(float shadowRadius);
@@ -873,7 +877,9 @@
bool mPendingHWCDestroy{false};
- bool backpressureEnabled() { return mDrawingState.flags & layer_state_t::eEnableBackpressure; }
+ bool backpressureEnabled() const {
+ return mDrawingState.flags & layer_state_t::eEnableBackpressure;
+ }
bool setStretchEffect(const StretchEffect& effect);
StretchEffect getStretchEffect() const;
@@ -901,10 +907,11 @@
// TODO(b/238781169) Remove direct calls to RenderEngine::drawLayers that don't go through
// CompositionEngine to create a single path for composing layers.
void updateSnapshot(bool updateGeometry);
+ void updateMetadataSnapshot(const LayerMetadata& parentMetadata);
+ void updateRelativeMetadataSnapshot(const LayerMetadata& relativeLayerMetadata,
+ std::unordered_set<Layer*>& visited);
protected:
- friend class impl::SurfaceInterceptor;
-
// For unit tests
friend class TestableSurfaceFlinger;
friend class FpsReporterTest;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index d3f53c1..a6cd47b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -237,16 +237,13 @@
EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
android::frametimeline::TokenManager* tokenManager,
- InterceptVSyncsCallback interceptVSyncsCallback,
ThrottleVsyncCallback throttleVsyncCallback,
GetVsyncPeriodFunction getVsyncPeriodFunction)
: mVSyncSource(std::move(vsyncSource)),
mTokenManager(tokenManager),
- mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)),
mThreadName(mVSyncSource->getName()) {
-
LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr,
"getVsyncPeriodFunction must not be null");
@@ -443,21 +440,13 @@
event = mPendingEvents.front();
mPendingEvents.pop_front();
- switch (event->header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
- if (event->hotplug.connected && !mVSyncState) {
- mVSyncState.emplace(event->header.displayId);
- } else if (!event->hotplug.connected && mVSyncState &&
- mVSyncState->displayId == event->header.displayId) {
- mVSyncState.reset();
- }
- break;
-
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- if (mInterceptVSyncsCallback) {
- mInterceptVSyncsCallback(event->header.timestamp);
- }
- break;
+ if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
+ if (event->hotplug.connected && !mVSyncState) {
+ mVSyncState.emplace(event->header.displayId);
+ } else if (!event->hotplug.connected && mVSyncState &&
+ mVSyncState->displayId == event->header.displayId) {
+ mVSyncState.reset();
+ }
}
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index d85d140..7a5a348 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -161,12 +161,11 @@
class EventThread : public android::EventThread, private VSyncSource::Callback {
public:
- using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
using ThrottleVsyncCallback = std::function<bool(nsecs_t, uid_t)>;
using GetVsyncPeriodFunction = std::function<nsecs_t(uid_t)>;
- EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*, InterceptVSyncsCallback,
- ThrottleVsyncCallback, GetVsyncPeriodFunction);
+ EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*, ThrottleVsyncCallback,
+ GetVsyncPeriodFunction);
~EventThread();
sp<EventThreadConnection> createEventConnection(
@@ -225,7 +224,6 @@
const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
frametimeline::TokenManager* const mTokenManager;
- const InterceptVSyncsCallback mInterceptVSyncsCallback;
const ThrottleVsyncCallback mThrottleVsyncCallback;
const GetVsyncPeriodFunction mGetVsyncPeriodFunction;
const char* const mThreadName;
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
deleted file mode 100644
index 760a4ee..0000000
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2018 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 <mutex>
-
-#include "EventThread.h"
-
-namespace android {
-
-/**
- * VSync signals used during SurfaceFlinger trace playback (traces we captured
- * with SurfaceInterceptor).
- */
-class InjectVSyncSource final : public VSyncSource {
-public:
- ~InjectVSyncSource() override = default;
-
- void setCallback(VSyncSource::Callback* callback) override {
- std::lock_guard<std::mutex> lock(mCallbackMutex);
- mCallback = callback;
- }
-
- void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
- nsecs_t deadlineTimestamp) {
- std::lock_guard<std::mutex> lock(mCallbackMutex);
- if (mCallback) {
- mCallback->onVSyncEvent(when, {expectedVSyncTimestamp, deadlineTimestamp});
- }
- }
-
- const char* getName() const override { return "inject"; }
- void setVSyncEnabled(bool) override {}
- void setDuration(std::chrono::nanoseconds, std::chrono::nanoseconds) override {}
- VSyncData getLatestVSyncData() const override { return {}; }
- void dump(std::string&) const override {}
-
-private:
- std::mutex mCallbackMutex;
- VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index e4e65b4..ae10ff4 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -57,37 +57,6 @@
mLooper(sp<Looper>::make(kAllowNonCallbacks)),
mHandler(std::move(handler)) {}
-// TODO(b/169865816): refactor VSyncInjections to use MessageQueue directly
-// and remove the EventThread from MessageQueue
-void MessageQueue::setInjector(sp<EventThreadConnection> connection) {
- auto& tube = mInjector.tube;
-
- if (const int fd = tube.getFd(); fd >= 0) {
- mLooper->removeFd(fd);
- }
-
- if (connection) {
- // The EventThreadConnection is retained when disabling injection, so avoid subsequently
- // stealing invalid FDs. Note that the stolen FDs are kept open.
- if (tube.getFd() < 0) {
- connection->stealReceiveChannel(&tube);
- } else {
- ALOGW("Recycling channel for VSYNC injection.");
- }
-
- mLooper->addFd(
- tube.getFd(), 0, Looper::EVENT_INPUT,
- [](int, int, void* data) {
- reinterpret_cast<MessageQueue*>(data)->injectorCallback();
- return 1; // Keep registration.
- },
- this);
- }
-
- std::lock_guard lock(mInjector.mutex);
- mInjector.connection = std::move(connection);
-}
-
void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
ATRACE_CALL();
// Trace VSYNC-sf
@@ -174,15 +143,6 @@
void MessageQueue::scheduleFrame() {
ATRACE_CALL();
- {
- std::lock_guard lock(mInjector.mutex);
- if (CC_UNLIKELY(mInjector.connection)) {
- ALOGD("%s while injecting VSYNC", __func__);
- mInjector.connection->requestNextVsync();
- return;
- }
- }
-
std::lock_guard lock(mVsync.mutex);
mVsync.scheduledFrameTime =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
@@ -190,22 +150,6 @@
.earliestVsync = mVsync.lastCallbackTime.ns()});
}
-void MessageQueue::injectorCallback() {
- ssize_t n;
- DisplayEventReceiver::Event buffer[8];
- 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) {
- auto& vsync = buffer[i].vsync.vsyncData;
- mHandler->dispatchFrame(VsyncId{vsync.preferredVsyncId()},
- TimePoint::fromNs(
- vsync.preferredExpectedPresentationTime()));
- break;
- }
- }
- }
-}
-
auto MessageQueue::getScheduledFrameTime() const -> std::optional<Clock::time_point> {
if (mHandler->isFramePending()) {
return Clock::now();
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 899233a..04de492 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -76,7 +76,6 @@
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 scheduleConfigure() = 0;
@@ -132,16 +131,7 @@
TracedOrdinal<int> value = {"VSYNC-sf", 0};
};
- struct Injector {
- gui::BitTube tube;
- std::mutex mutex;
- sp<EventThreadConnection> connection GUARDED_BY(mutex);
- };
-
Vsync mVsync;
- Injector mInjector;
-
- void injectorCallback();
public:
explicit MessageQueue(ICompositor&);
@@ -149,7 +139,6 @@
void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
std::chrono::nanoseconds workDuration) override;
void setDuration(std::chrono::nanoseconds workDuration) override;
- void setInjector(sp<EventThreadConnection>) override;
void waitMessage() override;
void postMessage(sp<MessageHandler>&&) override;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3cb052c..30483a2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -28,6 +28,7 @@
#include <android-base/stringprintf.h>
#include <ftl/enum.h>
#include <ftl/fake_guard.h>
+#include <ftl/match.h>
#include <utils/Trace.h>
#include "../SurfaceFlingerProperties.h"
@@ -117,6 +118,20 @@
return false;
}
+std::string toString(const RefreshRateConfigs::PolicyVariant& policy) {
+ using namespace std::string_literals;
+
+ return ftl::match(
+ policy,
+ [](const RefreshRateConfigs::DisplayManagerPolicy& policy) {
+ return "DisplayManagerPolicy"s + policy.toString();
+ },
+ [](const RefreshRateConfigs::OverridePolicy& policy) {
+ return "OverridePolicy"s + policy.toString();
+ },
+ [](RefreshRateConfigs::NoOverridePolicy) { return "NoOverridePolicy"s; });
+}
+
} // namespace
struct RefreshRateConfigs::RefreshRateScoreComparator {
@@ -299,7 +314,8 @@
// Keep the display at max refresh rate for the duration of powering on the display.
if (signals.powerOnImminent) {
ALOGV("Power On Imminent");
- return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending),
+ return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Descending,
+ /*preferredDisplayModeOpt*/ std::nullopt),
GlobalSignals{.powerOnImminent = true}};
}
@@ -359,7 +375,8 @@
// selected a refresh rate to see if we should apply touch boost.
if (signals.touch && !hasExplicitVoteLayers) {
ALOGV("Touch Boost");
- return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
+ return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
+ /*preferredDisplayModeOpt*/ std::nullopt),
GlobalSignals{.touch = true}};
}
@@ -371,20 +388,23 @@
if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
ALOGV("Idle");
- return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending),
+ return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending,
+ /*preferredDisplayModeOpt*/ std::nullopt),
GlobalSignals{.idle = true}};
}
if (layers.empty() || noVoteLayers == layers.size()) {
ALOGV("No layers with votes");
- return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
+ return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
+ /*preferredDisplayModeOpt*/ std::nullopt),
kNoSignals};
}
// Only if all layers want Min we should return Min
if (noVoteLayers + minVoteLayers == layers.size()) {
ALOGV("All layers Min");
- return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending),
+ return {getRefreshRatesByPolicyLocked(activeMode.getGroup(), RefreshRateOrder::Ascending,
+ /*preferredDisplayModeOpt*/ std::nullopt),
kNoSignals};
}
@@ -545,13 +565,17 @@
return RefreshRateRanking{score.modeIt->second, score.overallScore};
});
+ const bool noLayerScore = std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) {
+ return score.overallScore == 0;
+ });
+
if (primaryRangeIsSingleRate) {
// If we never scored any layers, then choose the rate from the primary
// range instead of picking a random score from the app range.
- if (std::all_of(scores.begin(), scores.end(),
- [](RefreshRateScore score) { return score.overallScore == 0; })) {
+ if (noLayerScore) {
ALOGV("Layers not scored");
- return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending),
+ return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
+ /*preferredDisplayModeOpt*/ std::nullopt),
kNoSignals};
} else {
return {rankedRefreshRates, kNoSignals};
@@ -573,7 +597,8 @@
}();
const auto& touchRefreshRates =
- getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending);
+ getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Descending,
+ /*preferredDisplayModeOpt*/ std::nullopt);
using fps_approx_ops::operator<;
if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
@@ -583,6 +608,15 @@
return {touchRefreshRates, GlobalSignals{.touch = true}};
}
+ // If we never scored any layers, and we don't favor high refresh rates, prefer to stay with the
+ // current config
+ if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) {
+ const auto preferredDisplayMode = activeMode.getId();
+ return {getRefreshRatesByPolicyLocked(anchorGroup, RefreshRateOrder::Ascending,
+ preferredDisplayMode),
+ kNoSignals};
+ }
+
return {rankedRefreshRates, kNoSignals};
}
@@ -750,15 +784,29 @@
}
std::vector<RefreshRateRanking> RefreshRateConfigs::getRefreshRatesByPolicyLocked(
- std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const {
- std::vector<RefreshRateRanking> rankings;
+ std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder,
+ std::optional<DisplayModeId> preferredDisplayModeOpt) const {
+ std::deque<RefreshRateRanking> rankings;
const auto makeRanking = [&](const DisplayModeIterator it) REQUIRES(mLock) {
const auto& mode = it->second;
- const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending);
- const float score = calculateRefreshRateScoreForFps(mode->getFps());
- if (!anchorGroupOpt || mode->getGroup() == anchorGroupOpt) {
- rankings.push_back(RefreshRateRanking{mode, inverseScore ? 1.0f / score : score});
+ if (anchorGroupOpt && mode->getGroup() != anchorGroupOpt) {
+ return;
}
+
+ float score = calculateRefreshRateScoreForFps(mode->getFps());
+ const bool inverseScore = (refreshRateOrder == RefreshRateOrder::Ascending);
+ if (inverseScore) {
+ score = 1.0f / score;
+ }
+ if (preferredDisplayModeOpt) {
+ if (*preferredDisplayModeOpt == mode->getId()) {
+ rankings.push_front(RefreshRateRanking{mode, /*score*/ 1.0f});
+ return;
+ }
+ constexpr float kNonPreferredModePenalty = 0.95f;
+ score *= kNonPreferredModePenalty;
+ }
+ rankings.push_back(RefreshRateRanking{mode, score});
};
if (refreshRateOrder == RefreshRateOrder::Ascending) {
@@ -768,14 +816,15 @@
}
if (!rankings.empty() || !anchorGroupOpt) {
- return rankings;
+ return {rankings.begin(), rankings.end()};
}
ALOGW("Can't find %s refresh rate by policy with the same mode group"
" as the mode group %d",
refreshRateOrder == RefreshRateOrder::Ascending ? "min" : "max", anchorGroupOpt.value());
- return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder);
+ return getRefreshRatesByPolicyLocked(/*anchorGroupOpt*/ std::nullopt, refreshRateOrder,
+ preferredDisplayModeOpt);
}
DisplayModePtr RefreshRateConfigs::getActiveModePtr() const {
@@ -874,35 +923,60 @@
policy.appRequestRange.max >= policy.primaryRange.max;
}
-status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
- std::lock_guard lock(mLock);
- if (!isPolicyValidLocked(policy)) {
- ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
- return BAD_VALUE;
- }
- mGetRankedRefreshRatesCache.reset();
- Policy previousPolicy = *getCurrentPolicyLocked();
- mDisplayManagerPolicy = policy;
- if (*getCurrentPolicyLocked() == previousPolicy) {
- return CURRENT_POLICY_UNCHANGED;
- }
- constructAvailableRefreshRates();
- return NO_ERROR;
-}
+auto RefreshRateConfigs::setPolicy(const PolicyVariant& policy) -> SetPolicyResult {
+ Policy oldPolicy;
+ {
+ std::lock_guard lock(mLock);
+ oldPolicy = *getCurrentPolicyLocked();
-status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& policy) {
- std::lock_guard lock(mLock);
- if (policy && !isPolicyValidLocked(*policy)) {
- return BAD_VALUE;
+ const bool valid = ftl::match(
+ policy,
+ [this](const auto& policy) {
+ ftl::FakeGuard guard(mLock);
+ if (!isPolicyValidLocked(policy)) {
+ ALOGE("Invalid policy: %s", policy.toString().c_str());
+ return false;
+ }
+
+ using T = std::decay_t<decltype(policy)>;
+
+ if constexpr (std::is_same_v<T, DisplayManagerPolicy>) {
+ mDisplayManagerPolicy = policy;
+ } else {
+ static_assert(std::is_same_v<T, OverridePolicy>);
+ mOverridePolicy = policy;
+ }
+ return true;
+ },
+ [this](NoOverridePolicy) {
+ ftl::FakeGuard guard(mLock);
+ mOverridePolicy.reset();
+ return true;
+ });
+
+ if (!valid) {
+ return SetPolicyResult::Invalid;
+ }
+
+ mGetRankedRefreshRatesCache.reset();
+
+ if (*getCurrentPolicyLocked() == oldPolicy) {
+ return SetPolicyResult::Unchanged;
+ }
+ constructAvailableRefreshRates();
}
- mGetRankedRefreshRatesCache.reset();
- Policy previousPolicy = *getCurrentPolicyLocked();
- mOverridePolicy = policy;
- if (*getCurrentPolicyLocked() == previousPolicy) {
- return CURRENT_POLICY_UNCHANGED;
- }
- constructAvailableRefreshRates();
- return NO_ERROR;
+
+ const auto displayId = getActiveMode().getPhysicalDisplayId();
+ const unsigned numModeChanges = std::exchange(mNumModeSwitchesInPolicy, 0u);
+
+ ALOGI("Display %s policy changed\n"
+ "Previous: %s\n"
+ "Current: %s\n"
+ "%u mode changes were performed under the previous policy",
+ to_string(displayId).c_str(), oldPolicy.toString().c_str(), toString(policy).c_str(),
+ numModeChanges);
+
+ return SetPolicyResult::Changed;
}
const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const {
@@ -1037,47 +1111,45 @@
isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef));
}
-void RefreshRateConfigs::dump(std::string& result) const {
- using namespace std::string_literals;
+void RefreshRateConfigs::dump(utils::Dumper& dumper) const {
+ using namespace std::string_view_literals;
std::lock_guard lock(mLock);
const auto activeModeId = getActiveModeItLocked()->first;
- result += " activeModeId="s;
- result += std::to_string(activeModeId.value());
+ dumper.dump("activeModeId"sv, std::to_string(activeModeId.value()));
- result += "\n displayModes=\n"s;
- for (const auto& [id, mode] : mDisplayModes) {
- result += " "s;
- result += to_string(*mode);
- result += '\n';
+ dumper.dump("displayModes"sv);
+ {
+ utils::Dumper::Indent indent(dumper);
+ for (const auto& [id, mode] : mDisplayModes) {
+ dumper.dump({}, to_string(*mode));
+ }
}
- base::StringAppendF(&result, " displayManagerPolicy=%s\n",
- mDisplayManagerPolicy.toString().c_str());
+ dumper.dump("displayManagerPolicy"sv, mDisplayManagerPolicy.toString());
if (const Policy& currentPolicy = *getCurrentPolicyLocked();
mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
- base::StringAppendF(&result, " overridePolicy=%s\n", currentPolicy.toString().c_str());
+ dumper.dump("overridePolicy"sv, currentPolicy.toString());
}
- base::StringAppendF(&result, " supportsFrameRateOverrideByContent=%s\n",
- mSupportsFrameRateOverrideByContent ? "true" : "false");
+ dumper.dump("supportsFrameRateOverrideByContent"sv, mSupportsFrameRateOverrideByContent);
- result += " idleTimer="s;
+ std::string idleTimer;
if (mIdleTimer) {
- result += mIdleTimer->dump();
+ idleTimer = mIdleTimer->dump();
} else {
- result += "off"s;
+ idleTimer = "off"sv;
}
if (const auto controller = mConfig.kernelIdleTimerController) {
- base::StringAppendF(&result, " (kernel via %s)", ftl::enum_string(*controller).c_str());
+ base::StringAppendF(&idleTimer, " (kernel via %s)", ftl::enum_string(*controller).c_str());
} else {
- result += " (platform)"s;
+ idleTimer += " (platform)"sv;
}
- result += '\n';
+ dumper.dump("idleTimer"sv, idleTimer);
}
std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 0642fcb..7219584 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -21,6 +21,7 @@
#include <optional>
#include <type_traits>
#include <utility>
+#include <variant>
#include <gui/DisplayEventReceiver.h>
@@ -32,6 +33,7 @@
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/StrongTyping.h"
#include "ThreadContext.h"
+#include "Utils/Dumper.h"
namespace android::scheduler {
@@ -66,8 +68,7 @@
static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION =
std::chrono::nanoseconds(800us).count();
- struct Policy {
- private:
+ class Policy {
static constexpr int kAllowGroupSwitchingDefault = false;
public:
@@ -117,23 +118,28 @@
std::string toString() const;
};
- // Return code set*Policy() to indicate the current policy is unchanged.
- static constexpr int CURRENT_POLICY_UNCHANGED = 1;
+ enum class SetPolicyResult { Invalid, Unchanged, Changed };
// We maintain the display manager policy and the override policy separately. The override
// policy is used by CTS tests to get a consistent device state for testing. While the override
// policy is set, it takes precedence over the display manager policy. Once the override policy
// is cleared, we revert to using the display manager policy.
+ struct DisplayManagerPolicy : Policy {
+ using Policy::Policy;
+ };
- // Sets the display manager policy to choose refresh rates. The return value will be:
- // - A negative value if the policy is invalid or another error occurred.
- // - NO_ERROR if the policy was successfully updated, and the current policy is different from
- // what it was before the call.
- // - CURRENT_POLICY_UNCHANGED if the policy was successfully updated, but the current policy
- // is the same as it was before the call.
- status_t setDisplayManagerPolicy(const Policy& policy) EXCLUDES(mLock);
- // Sets the override policy. See setDisplayManagerPolicy() for the meaning of the return value.
- status_t setOverridePolicy(const std::optional<Policy>& policy) EXCLUDES(mLock);
+ struct OverridePolicy : Policy {
+ using Policy::Policy;
+ };
+
+ struct NoOverridePolicy {};
+
+ using PolicyVariant = std::variant<DisplayManagerPolicy, OverridePolicy, NoOverridePolicy>;
+
+ SetPolicyResult setPolicy(const PolicyVariant&) EXCLUDES(mLock) REQUIRES(kMainThreadContext);
+
+ void onModeChangeInitiated() REQUIRES(kMainThreadContext) { mNumModeSwitchesInPolicy++; }
+
// Gets the current policy, which will be the override policy if active, and the display manager
// policy otherwise.
Policy getCurrentPolicy() const EXCLUDES(mLock);
@@ -336,7 +342,7 @@
mIdleTimer->reset();
}
- void dump(std::string& result) const EXCLUDES(mLock);
+ void dump(utils::Dumper&) const EXCLUDES(mLock);
std::chrono::milliseconds getIdleTimerTimeout();
@@ -369,9 +375,9 @@
// Returns the rankings in RefreshRateOrder. May change at runtime.
// Only uses the primary range, not the app request range.
- std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked(std::optional<int> anchorGroupOpt,
- RefreshRateOrder) const
- REQUIRES(mLock);
+ std::vector<RefreshRateRanking> getRefreshRatesByPolicyLocked(
+ std::optional<int> anchorGroupOpt, RefreshRateOrder,
+ std::optional<DisplayModeId> preferredDisplayModeOpt) const REQUIRES(mLock);
const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
@@ -417,6 +423,8 @@
Policy mDisplayManagerPolicy GUARDED_BY(mLock);
std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);
+ unsigned mNumModeSwitchesInPolicy GUARDED_BY(kMainThreadContext) = 0;
+
mutable std::mutex mLock;
// A sorted list of known frame rates that a Heuristic layer will choose
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6d68bac..30f2c27 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -26,6 +26,7 @@
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <ftl/fake_guard.h>
+#include <ftl/small_map.h>
#include <gui/WindowInfo.h>
#include <system/window.h>
#include <utils/Timers.h>
@@ -41,9 +42,9 @@
#include "../Layer.h"
#include "DispSyncSource.h"
+#include "Display/DisplayMap.h"
#include "EventThread.h"
#include "FrameRateOverrideMappings.h"
-#include "InjectVSyncSource.h"
#include "OneShotTimer.h"
#include "SurfaceFlingerProperties.h"
#include "VSyncPredictor.h"
@@ -125,6 +126,15 @@
mRefreshRateConfigs->startIdleTimer();
}
+void Scheduler::registerDisplay(sp<const DisplayDevice> display) {
+ const bool ok = mDisplays.try_emplace(display->getPhysicalId(), std::move(display)).second;
+ ALOGE_IF(!ok, "%s: Duplicate display", __func__);
+}
+
+void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
+ mDisplays.erase(displayId);
+}
+
void Scheduler::run() {
while (true) {
waitMessage();
@@ -198,15 +208,14 @@
};
}
-ConnectionHandle Scheduler::createConnection(
- const char* connectionName, frametimeline::TokenManager* tokenManager,
- std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
- impl::EventThread::InterceptVSyncsCallback interceptCallback) {
+ConnectionHandle Scheduler::createConnection(const char* connectionName,
+ frametimeline::TokenManager* tokenManager,
+ std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) {
auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
auto throttleVsync = makeThrottleVsyncCallback();
auto getVsyncPeriod = makeGetVsyncPeriodFunction();
auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,
- std::move(interceptCallback),
std::move(throttleVsync),
std::move(getVsyncPeriod));
return createConnection(std::move(eventThread));
@@ -371,44 +380,6 @@
thread->setDuration(workDuration, readyDuration);
}
-ConnectionHandle Scheduler::enableVSyncInjection(bool enable) {
- if (mInjectVSyncs == enable) {
- return {};
- }
-
- ALOGV("%s VSYNC injection", enable ? "Enabling" : "Disabling");
-
- if (!mInjectorConnectionHandle) {
- auto vsyncSource = std::make_unique<InjectVSyncSource>();
- mVSyncInjector = vsyncSource.get();
-
- auto eventThread =
- std::make_unique<impl::EventThread>(std::move(vsyncSource),
- /*tokenManager=*/nullptr,
- impl::EventThread::InterceptVSyncsCallback(),
- impl::EventThread::ThrottleVsyncCallback(),
- impl::EventThread::GetVsyncPeriodFunction());
-
- // EventThread does not dispatch VSYNC unless the display is connected and powered on.
- eventThread->onHotplugReceived(PhysicalDisplayId::fromPort(0), true);
- eventThread->onScreenAcquired();
-
- mInjectorConnectionHandle = createConnection(std::move(eventThread));
- }
-
- mInjectVSyncs = enable;
- return mInjectorConnectionHandle;
-}
-
-bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t deadlineTimestamp) {
- if (!mInjectVSyncs || !mVSyncInjector) {
- return false;
- }
-
- mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime, deadlineTimestamp);
- return true;
-}
-
void Scheduler::enableHardwareVsync() {
std::lock_guard<std::mutex> lock(mHWVsyncLock);
if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
@@ -662,6 +633,7 @@
auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals {
DisplayModePtr newMode;
GlobalSignals consideredSignals;
+ std::vector<DisplayModeConfig> displayModeConfigs;
bool refreshRateChanged = false;
bool frameRateOverridesChanged;
@@ -674,9 +646,27 @@
if (currentState == newState) return {};
currentState = std::forward<T>(newState);
- const auto [rankings, signals] = getRankedDisplayModes();
- newMode = rankings.front().displayModePtr;
- consideredSignals = signals;
+ displayModeConfigs = getBestDisplayModeConfigs();
+
+ // mPolicy holds the current mode, using the current mode we find out
+ // what display is currently being tracked through the policy and
+ // then find the DisplayModeConfig for that display. So that
+ // later we check if the policy mode has changed for the same display in policy.
+ // If mPolicy mode isn't available then we take the first display from the best display
+ // modes as the candidate for policy changes and frame rate overrides.
+ // TODO(b/240743786) Update the single display based assumptions and make mode changes
+ // and mPolicy per display.
+ const DisplayModeConfig& displayModeConfigForCurrentPolicy = mPolicy.mode
+ ? *std::find_if(displayModeConfigs.begin(), displayModeConfigs.end(),
+ [&](const auto& displayModeConfig) REQUIRES(mPolicyLock) {
+ return displayModeConfig.displayModePtr
+ ->getPhysicalDisplayId() ==
+ mPolicy.mode->getPhysicalDisplayId();
+ })
+ : displayModeConfigs.front();
+
+ newMode = displayModeConfigForCurrentPolicy.displayModePtr;
+ consideredSignals = displayModeConfigForCurrentPolicy.signals;
frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
if (mPolicy.mode == newMode) {
@@ -691,9 +681,7 @@
}
}
if (refreshRateChanged) {
- mSchedulerCallback.requestDisplayMode(std::move(newMode),
- consideredSignals.idle ? DisplayModeEvent::None
- : DisplayModeEvent::Changed);
+ mSchedulerCallback.requestDisplayModes(std::move(displayModeConfigs));
}
if (frameRateOverridesChanged) {
mSchedulerCallback.triggerOnFrameRateOverridesChanged();
@@ -701,28 +689,109 @@
return consideredSignals;
}
-auto Scheduler::getRankedDisplayModes()
- -> std::pair<std::vector<RefreshRateRanking>, GlobalSignals> {
+std::vector<DisplayModeConfig> Scheduler::getBestDisplayModeConfigs() const {
ATRACE_CALL();
- const auto configs = holdRefreshRateConfigs();
+ using Rankings = std::pair<std::vector<RefreshRateRanking>, GlobalSignals>;
+ display::PhysicalDisplayVector<Rankings> perDisplayRankings;
+ // Tallies the score of a refresh rate across `displayCount` displays.
+ struct RefreshRateTally {
+ explicit RefreshRateTally(float score) : score(score) {}
+
+ float score;
+ size_t displayCount = 1;
+ };
+
+ // Chosen to exceed a typical number of refresh rates across displays.
+ constexpr size_t kStaticCapacity = 8;
+ ftl::SmallMap<Fps, RefreshRateTally, kStaticCapacity, FpsApproxEqual> refreshRateTallies;
+
+ const auto globalSignals = makeGlobalSignals();
+
+ for (const auto& [id, display] : mDisplays) {
+ auto [rankings, signals] =
+ display->holdRefreshRateConfigs()
+ ->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals);
+
+ for (const auto& [modePtr, score] : rankings) {
+ const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score);
+
+ if (!inserted) {
+ auto& tally = it->second;
+ tally.score += score;
+ tally.displayCount++;
+ }
+ }
+
+ perDisplayRankings.emplace_back(std::move(rankings), signals);
+ }
+
+ auto maxScoreIt = refreshRateTallies.cbegin();
+
+ // Find the first refresh rate common to all displays.
+ while (maxScoreIt != refreshRateTallies.cend() &&
+ maxScoreIt->second.displayCount != mDisplays.size()) {
+ ++maxScoreIt;
+ }
+
+ if (maxScoreIt != refreshRateTallies.cend()) {
+ // Choose the highest refresh rate common to all displays, if any.
+ for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) {
+ const auto [fps, tally] = *it;
+
+ if (tally.displayCount == mDisplays.size() && tally.score > maxScoreIt->second.score) {
+ maxScoreIt = it;
+ }
+ }
+ }
+
+ const std::optional<Fps> chosenFps = maxScoreIt != refreshRateTallies.cend()
+ ? std::make_optional(maxScoreIt->first)
+ : std::nullopt;
+
+ std::vector<DisplayModeConfig> displayModeConfigs;
+ displayModeConfigs.reserve(mDisplays.size());
+
+ using fps_approx_ops::operator==;
+
+ for (const auto& [rankings, signals] : perDisplayRankings) {
+ if (!chosenFps) {
+ displayModeConfigs.emplace_back(signals, rankings.front().displayModePtr);
+ continue;
+ }
+
+ for (const auto& ranking : rankings) {
+ const auto& modePtr = ranking.displayModePtr;
+ if (modePtr->getFps() == *chosenFps) {
+ displayModeConfigs.emplace_back(signals, modePtr);
+ break;
+ }
+ }
+ }
+ return displayModeConfigs;
+}
+
+GlobalSignals Scheduler::makeGlobalSignals() const {
const bool powerOnImminent = mDisplayPowerTimer &&
(mPolicy.displayPowerMode != hal::PowerMode::ON ||
mPolicy.displayPowerTimer == TimerState::Reset);
- const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active,
- .idle = mPolicy.idleTimer == TimerState::Expired,
- .powerOnImminent = powerOnImminent};
-
- return configs->getRankedRefreshRates(mPolicy.contentRequirements, signals);
+ return {.touch = mTouchTimer && mPolicy.touch == TouchState::Active,
+ .idle = mPolicy.idleTimer == TimerState::Expired,
+ .powerOnImminent = powerOnImminent};
}
DisplayModePtr Scheduler::getPreferredDisplayMode() {
std::lock_guard<std::mutex> lock(mPolicyLock);
// Make sure the stored mode is up to date.
if (mPolicy.mode) {
- mPolicy.mode = getRankedDisplayModes().first.front().displayModePtr;
+ const auto configs = holdRefreshRateConfigs();
+ const auto rankings =
+ configs->getRankedRefreshRates(mPolicy.contentRequirements, makeGlobalSignals())
+ .first;
+
+ mPolicy.mode = rankings.front().displayModePtr;
}
return mPolicy.mode;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index f567205..6633b05 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -24,6 +24,7 @@
#include <mutex>
#include <optional>
#include <unordered_map>
+#include <utility>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
@@ -34,7 +35,10 @@
#include <scheduler/Features.h>
#include <scheduler/Time.h>
+#include <ui/DisplayId.h>
+#include "Display/DisplayMap.h"
+#include "DisplayDevice.h"
#include "EventThread.h"
#include "FrameRateOverrideMappings.h"
#include "LayerHistory.h"
@@ -75,7 +79,6 @@
namespace android {
class FenceTime;
-class InjectVSyncSource;
namespace frametimeline {
class TokenManager;
@@ -83,11 +86,22 @@
namespace scheduler {
+using GlobalSignals = RefreshRateConfigs::GlobalSignals;
+
+// Config representing the DisplayMode and considered signals for the Display.
+struct DisplayModeConfig {
+ const GlobalSignals signals;
+ const DisplayModePtr displayModePtr;
+
+ DisplayModeConfig(GlobalSignals signals, DisplayModePtr displayModePtr)
+ : signals(signals), displayModePtr(std::move(displayModePtr)) {}
+};
+
struct ISchedulerCallback {
using DisplayModeEvent = scheduler::DisplayModeEvent;
virtual void setVsyncEnabled(bool) = 0;
- virtual void requestDisplayMode(DisplayModePtr, DisplayModeEvent) = 0;
+ virtual void requestDisplayModes(std::vector<DisplayModeConfig>) = 0;
virtual void kernelTimerChanged(bool expired) = 0;
virtual void triggerOnFrameRateOverridesChanged() = 0;
@@ -106,12 +120,14 @@
void setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs>)
EXCLUDES(mRefreshRateConfigsLock);
+ void registerDisplay(sp<const DisplayDevice>);
+ void unregisterDisplay(PhysicalDisplayId);
+
void run();
void createVsyncSchedule(FeatureFlags);
using Impl::initVsync;
- using Impl::setInjector;
using Impl::getScheduledFrameTime;
using Impl::setDuration;
@@ -129,8 +145,7 @@
ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*,
std::chrono::nanoseconds workDuration,
- std::chrono::nanoseconds readyDuration,
- android::impl::EventThread::InterceptVSyncsCallback);
+ std::chrono::nanoseconds readyDuration);
sp<IDisplayEventConnection> createDisplayEventConnection(
ConnectionHandle, EventRegistrationFlags eventRegistration = {});
@@ -150,10 +165,6 @@
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration);
- // Returns injector handle if injection has toggled, or an invalid handle otherwise.
- ConnectionHandle enableVSyncInjection(bool enable);
- // Returns false if injection is disabled.
- bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t deadlineTimestamp);
void enableHardwareVsync();
void disableHardwareVsync(bool makeUnavailable);
@@ -260,8 +271,6 @@
void setVsyncPeriod(nsecs_t period);
- using GlobalSignals = RefreshRateConfigs::GlobalSignals;
-
struct Policy;
// Sets the S state of the policy to the T value under mPolicyLock, and chooses a display mode
@@ -269,10 +278,10 @@
template <typename S, typename T>
GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock);
- // Returns the list of display modes in descending order of their priority that fulfills the
- // policy, and the signals that were considered.
- std::pair<std::vector<RefreshRateRanking>, GlobalSignals> getRankedDisplayModes()
- REQUIRES(mPolicyLock);
+ // Returns the best display mode per display.
+ std::vector<DisplayModeConfig> getBestDisplayModeConfigs() const REQUIRES(mPolicyLock);
+
+ GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock);
bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);
@@ -298,10 +307,6 @@
mutable std::mutex mConnectionsLock;
std::unordered_map<ConnectionHandle, Connection> mConnections GUARDED_BY(mConnectionsLock);
- bool mInjectVSyncs = false;
- InjectVSyncSource* mVSyncInjector = nullptr;
- ConnectionHandle mInjectorConnectionHandle;
-
mutable std::mutex mHWVsyncLock;
bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false;
bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false;
@@ -323,6 +328,8 @@
mutable std::mutex mPolicyLock;
+ display::PhysicalDisplayMap<PhysicalDisplayId, sp<const DisplayDevice>> mDisplays;
+
struct Policy {
// Policy for choosing the display mode.
LayerHistory::Summary contentRequirements;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8b19dcc..04eec94 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -129,19 +129,16 @@
#include "LayerVector.h"
#include "MutexUtils.h"
#include "NativeWindowSurface.h"
-#include "RefreshRateOverlay.h"
#include "RegionSamplingThread.h"
-#include "Scheduler/DispSyncSource.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/LayerHistory.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/VsyncConfiguration.h"
-#include "Scheduler/VsyncController.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlingerProperties.h"
-#include "SurfaceInterceptor.h"
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
+#include "Utils/Dumper.h"
#include "WindowInfosListenerInvoker.h"
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
@@ -181,7 +178,6 @@
using gui::LayerMetadata;
using gui::WindowInfo;
using gui::aidl_utils::binderStatusFromStatusT;
-using ui::ColorMode;
using ui::Dataspace;
using ui::DisplayPrimaries;
using ui::RenderIntent;
@@ -192,33 +188,6 @@
namespace {
-#pragma clang diagnostic push
-#pragma clang diagnostic error "-Wswitch-enum"
-
-bool isWideColorMode(const ColorMode colorMode) {
- switch (colorMode) {
- case ColorMode::DISPLAY_P3:
- case ColorMode::ADOBE_RGB:
- case ColorMode::DCI_P3:
- case ColorMode::BT2020:
- case ColorMode::DISPLAY_BT2020:
- case ColorMode::BT2100_PQ:
- case ColorMode::BT2100_HLG:
- return true;
- case ColorMode::NATIVE:
- case ColorMode::STANDARD_BT601_625:
- case ColorMode::STANDARD_BT601_625_UNADJUSTED:
- case ColorMode::STANDARD_BT601_525:
- case ColorMode::STANDARD_BT601_525_UNADJUSTED:
- case ColorMode::STANDARD_BT709:
- case ColorMode::SRGB:
- return false;
- }
- return false;
-}
-
-#pragma clang diagnostic pop
-
// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
@@ -290,7 +259,6 @@
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
uint32_t SurfaceFlinger::maxGraphicsWidth;
uint32_t SurfaceFlinger::maxGraphicsHeight;
-bool SurfaceFlinger::hasWideColorDisplay;
bool SurfaceFlinger::useContextPriority;
Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
@@ -331,7 +299,6 @@
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
mPid(getpid()),
- mInterceptor(mFactory.createSurfaceInterceptor()),
mTimeStats(std::make_shared<impl::TimeStats>()),
mFrameTracer(mFactory.createFrameTracer()),
mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)),
@@ -359,11 +326,11 @@
maxGraphicsWidth = std::max(max_graphics_width(0), 0);
maxGraphicsHeight = std::max(max_graphics_height(0), 0);
- hasWideColorDisplay = has_wide_color_display(false);
+ mSupportsWideColor = has_wide_color_display(false);
mDefaultCompositionDataspace =
static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
mWideColorGamutCompositionDataspace = static_cast<ui::Dataspace>(wcg_composition_dataspace(
- hasWideColorDisplay ? Dataspace::DISPLAY_P3 : Dataspace::V0_SRGB));
+ mSupportsWideColor ? Dataspace::DISPLAY_P3 : Dataspace::V0_SRGB));
defaultCompositionDataspace = mDefaultCompositionDataspace;
wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace;
defaultCompositionPixelFormat = static_cast<ui::PixelFormat>(
@@ -526,7 +493,6 @@
state.isSecure = secure;
state.displayName = displayName;
mCurrentState.displays.add(token, state);
- mInterceptor->saveDisplayCreation(state);
return token;
}
@@ -544,7 +510,6 @@
ALOGE("%s: Invalid operation on physical display", __func__);
return;
}
- mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
setTransactionFlags(eDisplayTransactionNeeded);
}
@@ -775,6 +740,7 @@
void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
+ addTransactionReadyFilters();
Mutex::Autolock lock(mStateLock);
// Get a RenderEngine for the given display / config (can't fail)
@@ -895,8 +861,8 @@
property_get("persist.sys.sf.native_mode", value, "0");
mDisplayColorSetting = static_cast<DisplayColorSetting>(atoi(value));
- property_get("persist.sys.sf.color_mode", value, "0");
- mForceColorMode = static_cast<ColorMode>(atoi(value));
+ mForceColorMode =
+ static_cast<ui::ColorMode>(base::GetIntProperty("persist.sys.sf.color_mode"s, 0));
}
void SurfaceFlinger::startBootAnim() {
@@ -1058,11 +1024,12 @@
info->supportedDisplayModes.push_back(outMode);
}
+ info->supportedColorModes = snapshot.filterColorModes(mSupportsWideColor);
+
const PhysicalDisplayId displayId = snapshot.displayId();
info->activeDisplayModeId = display->refreshRateConfigs().getActiveModePtr()->getId().value();
info->activeColorMode = display->getCompositionDisplay()->getState().colorMode;
- info->supportedColorModes = getDisplayColorModes(displayId);
info->hdrCapabilities = display->getHdrCapabilities();
info->autoLowLatencyModeSupported =
@@ -1132,7 +1099,7 @@
}
const char* const whence = __func__;
- auto future = mScheduler->schedule([=]() -> status_t {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(kMainThreadContext) -> status_t {
const auto displayOpt =
FTL_FAKE_GUARD(mStateLock,
ftl::find_if(mPhysicalDisplays,
@@ -1157,13 +1124,16 @@
}
const Fps fps = *fpsOpt;
+
// Keep the old switching type.
const bool allowGroupSwitching =
display->refreshRateConfigs().getCurrentPolicy().allowGroupSwitching;
- const scheduler::RefreshRateConfigs::Policy policy{modeId, allowGroupSwitching, {fps, fps}};
- constexpr bool kOverridePolicy = false;
- return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
+ const scheduler::RefreshRateConfigs::DisplayManagerPolicy policy{modeId,
+ allowGroupSwitching,
+ {fps, fps}};
+
+ return setDesiredDisplayModeSpecsInternal(display, policy);
});
return future.get();
@@ -1214,7 +1184,7 @@
void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& display) {
display->clearDesiredActiveModeState();
- if (isDisplayActiveLocked(display)) {
+ if (display->getPhysicalId() == mActiveDisplayId) {
mScheduler->setModeChangePending(false);
}
}
@@ -1244,12 +1214,12 @@
// Store the local variable to release the lock.
const auto desiredActiveMode = display->getDesiredActiveMode();
if (!desiredActiveMode) {
- // No desired active mode pending to be applied
+ // No desired active mode pending to be applied.
continue;
}
- if (!isDisplayActiveLocked(display)) {
- // display is no longer the active display, so abort the mode change
+ if (id != mActiveDisplayId) {
+ // Display is no longer the active display, so abort the mode change.
clearDesiredActiveModeState(display);
continue;
}
@@ -1300,6 +1270,8 @@
ALOGW("initiateModeChange failed: %d", status);
continue;
}
+
+ display->refreshRateConfigs().onModeChangeInitiated();
mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
if (outTimeline.refreshRequired) {
@@ -1340,25 +1312,6 @@
future.wait();
}
-std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) {
- auto modes = getHwComposer().getColorModes(displayId);
-
- const bool isInternalDisplay = mPhysicalDisplays.get(displayId)
- .transform(&PhysicalDisplay::isInternal)
- .value_or(false);
-
- // If the display is internal and the configuration claims it's not wide color capable,
- // filter out all wide color modes. The typical reason why this happens is that the
- // hardware is not good enough to support GPU composition of wide color, and thus the
- // OEMs choose to disable this capability.
- if (isInternalDisplay && !hasWideColorDisplay) {
- const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode);
- modes.erase(newEnd, modes.end());
- }
-
- return modes;
-}
-
status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
ui::DisplayPrimaries& primaries) {
if (!displayToken) {
@@ -1382,31 +1335,32 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
+status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode mode) {
if (!displayToken) {
return BAD_VALUE;
}
+ const char* const whence = __func__;
auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
- const auto display = getDisplayDeviceLocked(displayToken);
- if (!display) {
- ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
- decodeColorMode(mode).c_str(), mode, displayToken.get());
+ const auto displayOpt =
+ ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken))
+ .transform(&ftl::to_mapped_ref<PhysicalDisplays>)
+ .and_then(getDisplayDeviceAndSnapshot());
+
+ if (!displayOpt) {
+ ALOGE("%s: Invalid physical display token %p", whence, displayToken.get());
return NAME_NOT_FOUND;
}
- if (display->isVirtual()) {
- ALOGW("Attempt to set active color mode %s (%d) for virtual display",
- decodeColorMode(mode).c_str(), mode);
- return INVALID_OPERATION;
- }
+ const auto& [display, snapshotRef] = *displayOpt;
+ const auto& snapshot = snapshotRef.get();
- const auto modes = getDisplayColorModes(display->getPhysicalId());
+ const auto modes = snapshot.filterColorModes(mSupportsWideColor);
const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end();
- if (mode < ColorMode::NATIVE || !exists) {
- ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
- decodeColorMode(mode).c_str(), mode, displayToken.get());
+ if (mode < ui::ColorMode::NATIVE || !exists) {
+ ALOGE("%s: Invalid color mode %s (%d) for display %s", whence,
+ decodeColorMode(mode).c_str(), mode, to_string(snapshot.displayId()).c_str());
return BAD_VALUE;
}
@@ -1588,31 +1542,10 @@
}
*outIsWideColorDisplay =
- display->isPrimary() ? hasWideColorDisplay : display->hasWideColorGamut();
+ display->isPrimary() ? mSupportsWideColor : display->hasWideColorGamut();
return NO_ERROR;
}
-status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
- auto future = mScheduler->schedule([=] {
- Mutex::Autolock lock(mStateLock);
-
- if (const auto handle = mScheduler->enableVSyncInjection(enable)) {
- mScheduler->setInjector(enable ? mScheduler->getEventConnection(handle) : nullptr);
- }
- });
-
- future.wait();
- return NO_ERROR;
-}
-
-status_t SurfaceFlinger::injectVSync(nsecs_t when) {
- Mutex::Autolock lock(mStateLock);
- const nsecs_t expectedPresentTime = calculateExpectedPresentTime(TimePoint::fromNs(when)).ns();
- const nsecs_t deadlineTimestamp = expectedPresentTime;
- return mScheduler->injectVSync(when, expectedPresentTime, deadlineTimestamp) ? NO_ERROR
- : BAD_VALUE;
-}
-
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) {
outLayers->clear();
auto future = mScheduler->schedule([=] {
@@ -1897,20 +1830,13 @@
ATRACE_FORMAT("onComposerHalVsync%s", tracePeriod.c_str());
Mutex::Autolock lock(mStateLock);
- const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId);
- if (displayId) {
- const auto token = getPhysicalDisplayTokenLocked(*displayId);
- const auto display = getDisplayDeviceLocked(token);
- display->onVsync(timestamp);
- }
if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
return;
}
- const bool isActiveDisplay =
- displayId && getPhysicalDisplayTokenLocked(*displayId) == mActiveDisplayToken;
- if (!isActiveDisplay) {
+ if (const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId);
+ displayId != mActiveDisplayId) {
// For now, we don't do anything with non active display vsyncs.
return;
}
@@ -2106,8 +2032,7 @@
// Save this once per commit + composite to ensure consistency
// TODO (b/240619471): consider removing active display check once AOD is fixed
- const auto activeDisplay =
- FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(mActiveDisplayToken));
+ const auto activeDisplay = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(mActiveDisplayId));
mPowerHintSessionEnabled = mPowerAdvisor->usePowerHintSession() && activeDisplay &&
activeDisplay->getPowerMode() == hal::PowerMode::ON;
if (mPowerHintSessionEnabled) {
@@ -2215,6 +2140,13 @@
}
mPowerAdvisor->setDisplays(displayIds);
+ const bool updateTaskMetadata = mCompositionEngine->getFeatureFlags().test(
+ compositionengine::Feature::kSnapshotLayerMetadata);
+ if (updateTaskMetadata && (mVisibleRegionsDirty || mLayerMetadataSnapshotNeeded)) {
+ updateLayerMetadataSnapshot();
+ mLayerMetadataSnapshotNeeded = false;
+ }
+
if (DOES_CONTAIN_BORDER) {
refreshArgs.borderInfoList.clear();
mDrawingState.traverse([&refreshArgs](Layer* layer) {
@@ -2737,8 +2669,6 @@
const auto& display = displayOpt->get();
if (const ssize_t index = mCurrentState.displays.indexOfKey(display.token()); index >= 0) {
- const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
- mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
}
@@ -2754,6 +2684,8 @@
return nullptr;
}
+ ui::ColorModes colorModes = getHwComposer().getColorModes(displayId);
+
if (displayOpt) {
const auto& display = displayOpt->get();
const auto& snapshot = display.snapshot();
@@ -2768,7 +2700,7 @@
const auto it =
mPhysicalDisplays.try_replace(displayId, display.token(), displayId,
snapshot.connectionType(), std::move(displayModes),
- std::move(deviceProductInfo));
+ std::move(colorModes), std::move(deviceProductInfo));
auto& state = mCurrentState.displays.editValueFor(it->second.token());
state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
@@ -2780,7 +2712,8 @@
mPhysicalDisplays.try_emplace(displayId, token, displayId,
getHwComposer().getDisplayConnectionType(displayId),
- std::move(displayModes), std::move(info.deviceProductInfo));
+ std::move(displayModes), std::move(colorModes),
+ std::move(info.deviceProductInfo));
DisplayDeviceState state;
state.physical = {.id = displayId,
@@ -2790,7 +2723,6 @@
state.displayName = std::move(info.name);
mCurrentState.displays.add(token, state);
- mInterceptor->saveDisplayCreation(state);
return "Connecting";
}
@@ -2835,22 +2767,20 @@
config);
})
.value_or(nullptr);
- }
- if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
- creationArgs.isPrimary = id == getPrimaryDisplayIdLocked();
+ creationArgs.isPrimary = physical->id == getPrimaryDisplayIdLocked();
if (useColorManagement) {
- std::vector<ColorMode> modes = getHwComposer().getColorModes(*id);
- for (ColorMode colorMode : modes) {
- if (isWideColorMode(colorMode)) {
- creationArgs.hasWideColorGamut = true;
- }
-
- std::vector<RenderIntent> renderIntents =
- getHwComposer().getRenderIntents(*id, colorMode);
- creationArgs.hwcColorModes.emplace(colorMode, renderIntents);
- }
+ mPhysicalDisplays.get(physical->id)
+ .transform(&PhysicalDisplay::snapshotRef)
+ .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
+ for (const auto mode : snapshot.colorModes()) {
+ creationArgs.hasWideColorGamut |= ui::isWideColorMode(mode);
+ creationArgs.hwcColorModes
+ .emplace(mode,
+ getHwComposer().getRenderIntents(physical->id, mode));
+ }
+ }));
}
}
@@ -2882,10 +2812,10 @@
nativeWindowSurface->preallocateBuffers();
- ColorMode defaultColorMode = ColorMode::NATIVE;
+ ui::ColorMode defaultColorMode = ui::ColorMode::NATIVE;
Dataspace defaultDataSpace = Dataspace::UNKNOWN;
if (display->hasWideColorGamut()) {
- defaultColorMode = ColorMode::SRGB;
+ defaultColorMode = ui::ColorMode::SRGB;
defaultDataSpace = Dataspace::V0_SRGB;
}
display->getCompositionDisplay()->setColorProfile(
@@ -2984,7 +2914,7 @@
if (display->isPrimary()) {
mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
}
-
+ mScheduler->registerDisplay(display);
dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
}
@@ -3000,6 +2930,7 @@
releaseVirtualDisplay(display->getVirtualId());
} else {
dispatchDisplayHotplugEvent(display->getPhysicalId(), false);
+ mScheduler->unregisterDisplay(display->getPhysicalId());
}
}
@@ -3036,6 +2967,8 @@
display->disconnect();
if (display->isVirtual()) {
releaseVirtualDisplay(display->getVirtualId());
+ } else {
+ mScheduler->unregisterDisplay(display->getPhysicalId());
}
}
@@ -3072,7 +3005,7 @@
(currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) {
display->setProjection(currentState.orientation, currentState.layerStackSpaceRect,
currentState.orientedDisplaySpaceRect);
- if (isDisplayActiveLocked(display)) {
+ if (display->getId() == mActiveDisplayId) {
mActiveDisplayTransformHint = display->getTransformHint();
}
}
@@ -3080,7 +3013,7 @@
currentState.height != drawingState.height) {
display->setDisplaySize(currentState.width, currentState.height);
- if (isDisplayActiveLocked(display)) {
+ if (display->getId() == mActiveDisplayId) {
onActiveDisplaySizeChanged(display);
}
}
@@ -3230,7 +3163,6 @@
}
doCommitTransactions();
- signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
}
void SurfaceFlinger::updateInputFlinger() {
@@ -3366,25 +3298,34 @@
mCompositionEngine->updateCursorAsync(refreshArgs);
}
-void SurfaceFlinger::requestDisplayMode(DisplayModePtr mode, DisplayModeEvent event) {
+void SurfaceFlinger::requestDisplayModes(
+ std::vector<scheduler::DisplayModeConfig> displayModeConfigs) {
+ if (mBootStage != BootStage::FINISHED) {
+ ALOGV("Currently in the boot stage, skipping display mode changes");
+ return;
+ }
+
+ ATRACE_CALL();
// If this is called from the main thread mStateLock must be locked before
// Currently the only way to call this function from the main thread is from
// Scheduler::chooseRefreshRateForContent
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display || mBootStage != BootStage::FINISHED) {
- return;
- }
- ATRACE_CALL();
-
- if (!display->refreshRateConfigs().isModeAllowed(mode->getId())) {
- ALOGV("Skipping disallowed mode %d", mode->getId().value());
- return;
- }
-
- setDesiredActiveMode({std::move(mode), event});
+ std::for_each(displayModeConfigs.begin(), displayModeConfigs.end(),
+ [&](const auto& config) REQUIRES(mStateLock) {
+ const auto& displayModePtr = config.displayModePtr;
+ if (const auto display =
+ getDisplayDeviceLocked(displayModePtr->getPhysicalDisplayId());
+ display->refreshRateConfigs().isModeAllowed(displayModePtr->getId())) {
+ const auto event = config.signals.idle ? DisplayModeEvent::None
+ : DisplayModeEvent::Changed;
+ setDesiredActiveMode({displayModePtr, event});
+ } else {
+ ALOGV("Skipping disallowed mode %d for display %" PRId64,
+ displayModePtr->getId().value(), display->getPhysicalId().value);
+ }
+ });
}
void SurfaceFlinger::triggerOnFrameRateOverridesChanged() {
@@ -3433,6 +3374,7 @@
mScheduler->createVsyncSchedule(features);
mScheduler->setRefreshRateConfigs(std::move(configs));
+ mScheduler->registerDisplay(display);
}
setVsyncEnabled(false);
mScheduler->startTimers();
@@ -3442,15 +3384,11 @@
mAppConnectionHandle =
mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
/*workDuration=*/configs.late.appWorkDuration,
- /*readyDuration=*/configs.late.sfWorkDuration,
- impl::EventThread::InterceptVSyncsCallback());
+ /*readyDuration=*/configs.late.sfWorkDuration);
mSfConnectionHandle =
mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(),
/*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
- /*readyDuration=*/configs.late.sfWorkDuration,
- [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- });
+ /*readyDuration=*/configs.late.sfWorkDuration);
mScheduler->initVsync(mScheduler->getVsyncSchedule().getDispatch(),
*mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration);
@@ -3694,122 +3632,117 @@
}
}
-int SurfaceFlinger::flushPendingTransactionQueues(
- std::vector<TransactionState>& transactions,
- std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
- bool tryApplyUnsignaled) {
- std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions;
- int transactionsPendingBarrier = 0;
- auto it = mPendingTransactionQueues.begin();
- while (it != mPendingTransactionQueues.end()) {
- auto& [applyToken, transactionQueue] = *it;
- while (!transactionQueue.empty()) {
- // if we are in LatchUnsignaledConfig::AutoSingleLayer
- // then we should have only one applyToken for processing.
- // so we can stop further transactions on this applyToken.
- if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer &&
- !applyTokensWithUnsignaledTransactions.empty()) {
- ATRACE_NAME("stopTransactionProcessing");
- break;
- }
-
- auto& transaction = transactionQueue.front();
- const auto ready =
- transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- TimePoint::fromNs(transaction.desiredPresentTime),
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent, transactions.size(),
- tryApplyUnsignaled);
- ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
- if (ready == TransactionReadiness::NotReady) {
- setTransactionFlags(eTransactionFlushNeeded);
- break;
- }
- if (ready == TransactionReadiness::NotReadyBarrier) {
- transactionsPendingBarrier++;
- setTransactionFlags(eTransactionFlushNeeded);
- break;
- }
- transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
- const bool frameNumberChanged = state.bufferData->flags.test(
- BufferData::BufferDataChange::frameNumberChanged);
- if (frameNumberChanged) {
- bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber;
- } else {
- // Barrier function only used for BBQ which always includes a frame number
- bufferLayersReadyToPresent[state.surface] =
- std::numeric_limits<uint64_t>::max();
- }
- });
- const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled);
- if (appliedUnsignaled) {
- applyTokensWithUnsignaledTransactions.insert(transaction.applyToken);
- }
-
- transactions.emplace_back(std::move(transaction));
- transactionQueue.pop();
- mPendingTransactionCount--;
- ATRACE_INT("TransactionQueue", mPendingTransactionCount.load());
- }
-
- if (transactionQueue.empty()) {
- it = mPendingTransactionQueues.erase(it);
- } else {
- it = std::next(it, 1);
- }
+TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelineCheck(
+ const TransactionHandler::TransactionFlushState& flushState) {
+ using TransactionReadiness = TransactionHandler::TransactionReadiness;
+ const auto& transaction = *flushState.transaction;
+ ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64,
+ transaction.frameTimelineInfo.vsyncId);
+ TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime);
+ // Do not present if the desiredPresentTime has not passed unless it is more than
+ // one second in the future. We ignore timestamps more than 1 second in the future
+ // for stability reasons.
+ if (!transaction.isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime &&
+ desiredPresentTime < mExpectedPresentTime + 1s) {
+ ATRACE_NAME("not current");
+ return TransactionReadiness::NotReady;
}
- return transactionsPendingBarrier;
+
+ if (!mScheduler->isVsyncValid(mExpectedPresentTime, transaction.originUid)) {
+ ATRACE_NAME("!isVsyncValid");
+ return TransactionReadiness::NotReady;
+ }
+
+ // If the client didn't specify desiredPresentTime, use the vsyncId to determine the
+ // expected present time of this transaction.
+ if (transaction.isAutoTimestamp &&
+ frameIsEarly(mExpectedPresentTime, VsyncId{transaction.frameTimelineInfo.vsyncId})) {
+ ATRACE_NAME("frameIsEarly");
+ return TransactionReadiness::NotReady;
+ }
+ return TransactionReadiness::Ready;
+}
+
+TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck(
+ const TransactionHandler::TransactionFlushState& flushState) {
+ using TransactionReadiness = TransactionHandler::TransactionReadiness;
+ auto ready = TransactionReadiness::Ready;
+ flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const layer_state_t& s) -> bool {
+ sp<Layer> layer = Layer::fromHandle(s.surface).promote();
+ const auto& transaction = *flushState.transaction;
+ // check for barrier frames
+ if (s.bufferData->hasBarrier &&
+ ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) {
+ const bool willApplyBarrierFrame =
+ flushState.bufferLayersReadyToPresent.contains(s.surface.get()) &&
+ (flushState.bufferLayersReadyToPresent.get(s.surface.get()) >=
+ s.bufferData->barrierFrameNumber);
+ if (!willApplyBarrierFrame) {
+ ATRACE_NAME("NotReadyBarrier");
+ ready = TransactionReadiness::NotReadyBarrier;
+ return false;
+ }
+ }
+
+ // If backpressure is enabled and we already have a buffer to commit, keep
+ // the transaction in the queue.
+ const bool hasPendingBuffer =
+ flushState.bufferLayersReadyToPresent.contains(s.surface.get());
+ if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) {
+ ATRACE_NAME("hasPendingBuffer");
+ ready = TransactionReadiness::NotReady;
+ return false;
+ }
+
+ // check fence status
+ const bool allowLatchUnsignaled = shouldLatchUnsignaled(layer, s, transaction.states.size(),
+ flushState.firstTransaction);
+ ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(),
+ allowLatchUnsignaled ? "true" : "false");
+
+ const bool acquireFenceChanged = s.bufferData &&
+ s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
+ s.bufferData->acquireFence;
+ const bool fenceSignaled =
+ (!acquireFenceChanged ||
+ s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled);
+ if (!fenceSignaled) {
+ if (!allowLatchUnsignaled) {
+ ready = TransactionReadiness::NotReady;
+ auto& listener = s.bufferData->releaseBufferListener;
+ if (listener &&
+ (flushState.queueProcessTime - transaction.postTime) >
+ std::chrono::nanoseconds(4s).count()) {
+ mTransactionHandler.onTransactionQueueStalled(transaction, listener);
+ }
+ return false;
+ }
+
+ ready = enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer
+ ? TransactionReadiness::ReadyUnsignaledSingle
+ : TransactionReadiness::ReadyUnsignaled;
+ }
+ return true;
+ });
+ ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
+ return ready;
+}
+
+void SurfaceFlinger::addTransactionReadyFilters() {
+ mTransactionHandler.addTransactionReadyFilter(
+ std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1));
+ mTransactionHandler.addTransactionReadyFilter(
+ std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, std::placeholders::_1));
}
bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
// states) around outside the scope of the lock
- std::vector<TransactionState> transactions;
- // Layer handles that have transactions with buffers that are ready to be applied.
- std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>> bufferLayersReadyToPresent;
+ std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions();
{
Mutex::Autolock _l(mStateLock);
- {
- while (!mLocklessTransactionQueue.isEmpty()) {
- auto maybeTransaction = mLocklessTransactionQueue.pop();
- if (!maybeTransaction.has_value()) {
- break;
- }
- auto transaction = maybeTransaction.value();
- mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
- }
-
- // Transactions with a buffer pending on a barrier may be on a different applyToken
- // than the transaction which satisfies our barrier. In fact this is the exact use case
- // that the primitive is designed for. This means we may first process
- // the barrier dependent transaction, determine it ineligible to complete
- // and then satisfy in a later inner iteration of flushPendingTransactionQueues.
- // The barrier dependent transaction was eligible to be presented in this frame
- // but we would have prevented it without case. To fix this we continually
- // loop through flushPendingTransactionQueues until we perform an iteration
- // where the number of transactionsPendingBarrier doesn't change. This way
- // we can continue to resolve dependency chains of barriers as far as possible.
- int lastTransactionsPendingBarrier = 0;
- int transactionsPendingBarrier = 0;
- do {
- lastTransactionsPendingBarrier = transactionsPendingBarrier;
- transactionsPendingBarrier =
- flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
- /*tryApplyUnsignaled*/ false);
- } while (lastTransactionsPendingBarrier != transactionsPendingBarrier);
-
- // We collected all transactions that could apply without latching unsignaled buffers.
- // If we are allowing latch unsignaled of some form, now it's the time to go over the
- // transactions that were not applied and try to apply them unsignaled.
- if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
- flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
- /*tryApplyUnsignaled*/ true);
- }
-
- return applyTransactions(transactions, vsyncId);
- }
+ return applyTransactions(transactions, vsyncId);
}
}
@@ -3827,10 +3760,6 @@
transaction.permissions, transaction.hasListenerCallbacks,
transaction.listenerCallbacks, transaction.originPid,
transaction.originUid, transaction.id);
- if (transaction.transactionCommittedSignal) {
- mTransactionCommittedSignals.emplace_back(
- std::move(transaction.transactionCommittedSignal));
- }
}
if (mTransactionTracing) {
@@ -3840,7 +3769,7 @@
}
bool SurfaceFlinger::transactionFlushNeeded() {
- return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty();
+ return mTransactionHandler.hasPendingTransactions();
}
bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId) const {
@@ -3866,7 +3795,7 @@
}
bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
- size_t numStates, size_t totalTXapplied) const {
+ size_t numStates, bool firstTransaction) const {
if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
return false;
@@ -3885,9 +3814,9 @@
}
if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
- if (totalTXapplied > 0) {
- ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)",
- __func__, totalTXapplied);
+ if (!firstTransaction) {
+ ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; not first transaction)",
+ __func__);
return false;
}
@@ -3911,144 +3840,6 @@
return true;
}
-auto SurfaceFlinger::transactionIsReadyToBeApplied(
- TransactionState& transaction, const FrameTimelineInfo& info, bool isAutoTimestamp,
- TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states,
- const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>&
- bufferLayersReadyToPresent,
- size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness {
- ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId);
- // Do not present if the desiredPresentTime has not passed unless it is more than one second
- // in the future. We ignore timestamps more than 1 second in the future for stability reasons.
- if (!isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime &&
- desiredPresentTime < mExpectedPresentTime + 1s) {
- ATRACE_NAME("not current");
- return TransactionReadiness::NotReady;
- }
-
- if (!mScheduler->isVsyncValid(mExpectedPresentTime, originUid)) {
- ATRACE_NAME("!isVsyncValid");
- return TransactionReadiness::NotReady;
- }
-
- // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected
- // present time of this transaction.
- if (isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{info.vsyncId})) {
- ATRACE_NAME("frameIsEarly");
- return TransactionReadiness::NotReady;
- }
-
- bool fenceUnsignaled = false;
- auto queueProcessTime = systemTime();
- for (const ComposerState& state : states) {
- const layer_state_t& s = state.state;
-
- sp<Layer> layer = nullptr;
- if (s.surface) {
- layer = fromHandle(s.surface).promote();
- } else if (s.hasBufferChanges()) {
- ALOGW("Transaction with buffer, but no Layer?");
- continue;
- }
- if (!layer) {
- continue;
- }
-
- if (s.hasBufferChanges() && s.bufferData->hasBarrier &&
- ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) {
- const bool willApplyBarrierFrame =
- (bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end()) &&
- (bufferLayersReadyToPresent.at(s.surface) >= s.bufferData->barrierFrameNumber);
- if (!willApplyBarrierFrame) {
- ATRACE_NAME("NotReadyBarrier");
- return TransactionReadiness::NotReadyBarrier;
- }
- }
-
- const bool allowLatchUnsignaled = tryApplyUnsignaled &&
- shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied);
- ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(),
- allowLatchUnsignaled ? "true" : "false");
-
- const bool acquireFenceChanged = s.bufferData &&
- s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
- s.bufferData->acquireFence;
- fenceUnsignaled = fenceUnsignaled ||
- (acquireFenceChanged &&
- s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled);
-
- if (fenceUnsignaled && !allowLatchUnsignaled) {
- if (!transaction.sentFenceTimeoutWarning &&
- queueProcessTime - transaction.postTime > std::chrono::nanoseconds(4s).count()) {
- transaction.sentFenceTimeoutWarning = true;
- auto listener = s.bufferData->releaseBufferListener;
- if (listener) {
- listener->onTransactionQueueStalled();
- }
- }
-
- ATRACE_NAME("fence unsignaled");
- return TransactionReadiness::NotReady;
- }
-
- if (s.hasBufferChanges()) {
- // If backpressure is enabled and we already have a buffer to commit, keep the
- // transaction in the queue.
- const bool hasPendingBuffer = bufferLayersReadyToPresent.find(s.surface) !=
- bufferLayersReadyToPresent.end();
- if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) {
- ATRACE_NAME("hasPendingBuffer");
- return TransactionReadiness::NotReady;
- }
- }
- }
- return fenceUnsignaled ? TransactionReadiness::ReadyUnsignaled : TransactionReadiness::Ready;
-}
-
-void SurfaceFlinger::queueTransaction(TransactionState& state) {
- // Generate a CountDownLatch pending state if this is a synchronous transaction.
- if (state.flags & eSynchronous) {
- state.transactionCommittedSignal =
- std::make_shared<CountDownLatch>(CountDownLatch::eSyncTransaction);
- }
-
- mLocklessTransactionQueue.push(state);
- mPendingTransactionCount++;
- ATRACE_INT("TransactionQueue", mPendingTransactionCount.load());
-
- const auto schedule = [](uint32_t flags) {
- if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
- if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart;
- return TransactionSchedule::Late;
- }(state.flags);
-
- const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;
-
- setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint);
-}
-
-void SurfaceFlinger::waitForSynchronousTransaction(
- const CountDownLatch& transactionCommittedSignal) {
- // applyTransactionState is called on the main SF thread. While a given process may wish
- // to wait on synchronous transactions, the main SF thread should apply the transaction and
- // set the value to notify this after committed.
- if (!transactionCommittedSignal.wait_until(
- std::chrono::nanoseconds(mAnimationTransactionTimeout))) {
- ALOGE("setTransactionState timed out!");
- }
-}
-
-void SurfaceFlinger::signalSynchronousTransactions(const uint32_t flag) {
- for (auto it = mTransactionCommittedSignals.begin();
- it != mTransactionCommittedSignals.end();) {
- if ((*it)->countDown(flag)) {
- it = mTransactionCommittedSignals.erase(it);
- } else {
- it++;
- }
- }
-}
-
status_t SurfaceFlinger::setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
@@ -4099,12 +3890,16 @@
if (mTransactionTracing) {
mTransactionTracing->addQueuedTransaction(state);
}
- queueTransaction(state);
- // Check the pending state to make sure the transaction is synchronous.
- if (state.transactionCommittedSignal) {
- waitForSynchronousTransaction(*state.transactionCommittedSignal);
- }
+ const auto schedule = [](uint32_t flags) {
+ if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
+ if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart;
+ return TransactionSchedule::Late;
+ }(state.flags);
+
+ const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;
+ setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint);
+ mTransactionHandler.queueTransaction(std::move(state));
return NO_ERROR;
}
@@ -4162,18 +3957,12 @@
// anyway. This can be used as a flush mechanism for previous async transactions.
// Empty animation transaction can be used to simulate back-pressure, so also force a
// transaction for empty animation transactions.
- if (transactionFlags == 0 &&
- ((flags & eSynchronous) || (flags & eAnimation))) {
+ if (transactionFlags == 0 && (flags & eAnimation)) {
transactionFlags = eTransactionNeeded;
}
bool needsTraversal = false;
if (transactionFlags) {
- if (mInterceptor->isEnabled()) {
- mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
- originPid, originUid, transactionId);
- }
-
// We are on the main thread, we are about to preform a traversal. Clear the traversal bit
// so we don't have to wake up again next frame to preform an unnecessary traversal.
if (transactionFlags & eTraversalNeeded) {
@@ -4346,12 +4135,10 @@
}
}
if (what & layer_state_t::eAlphaChanged) {
- if (layer->setAlpha(s.alpha))
- flags |= eTraversalNeeded;
+ if (layer->setAlpha(s.color.a)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eColorChanged) {
- if (layer->setColor(s.color))
- flags |= eTraversalNeeded;
+ if (layer->setColor(s.color.rgb)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eColorTransformChanged) {
if (layer->setColorTransform(s.colorTransform)) {
@@ -4359,7 +4146,7 @@
}
}
if (what & layer_state_t::eBackgroundColorChanged) {
- if (layer->setBackgroundColor(s.color, s.bgColorAlpha, s.bgColorDataspace)) {
+ if (layer->setBackgroundColor(s.color.rgb, s.bgColorAlpha, s.bgColorDataspace)) {
flags |= eTraversalNeeded;
}
}
@@ -4408,8 +4195,8 @@
flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded;
}
}
- if (what & layer_state_t::eTransformChanged) {
- if (layer->setTransform(s.transform)) flags |= eTraversalNeeded;
+ if (what & layer_state_t::eBufferTransformChanged) {
+ if (layer->setTransform(s.bufferTransform)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eTransformToDisplayInverseChanged) {
if (layer->setTransformToDisplayInverse(s.transformToDisplayInverse))
@@ -4449,7 +4236,10 @@
layer->setGameModeForTree(static_cast<GameMode>(gameMode));
}
- if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
+ if (layer->setMetadata(s.metadata)) {
+ flags |= eTraversalNeeded;
+ mLayerMetadataSnapshotNeeded = true;
+ }
}
if (what & layer_state_t::eColorSpaceAgnosticChanged) {
if (layer->setColorSpaceAgnostic(s.colorSpaceAgnostic)) {
@@ -4568,8 +4358,8 @@
}
status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args,
- const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
- int32_t* outLayerId) {
+ const sp<IBinder>& mirrorFromHandle,
+ gui::CreateSurfaceResult& outResult) {
if (!mirrorFromHandle) {
return NAME_NOT_FOUND;
}
@@ -4584,7 +4374,7 @@
}
LayerCreationArgs mirrorArgs = args;
mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill;
- status_t result = createEffectLayer(mirrorArgs, outHandle, &mirrorLayer);
+ status_t result = createEffectLayer(mirrorArgs, &outResult.handle, &mirrorLayer);
if (result != NO_ERROR) {
return result;
}
@@ -4592,17 +4382,20 @@
mirrorLayer->setClonedChild(mirrorFrom->createClone());
}
- *outLayerId = mirrorLayer->sequence;
+ outResult.layerId = mirrorLayer->sequence;
+ outResult.layerName = String16(mirrorLayer->getDebugName());
if (mTransactionTracing) {
- mTransactionTracing->onMirrorLayerAdded((*outHandle)->localBinder(), mirrorLayer->sequence,
- args.name, mirrorFrom->sequence);
+ mTransactionTracing->onMirrorLayerAdded(outResult.handle->localBinder(),
+ mirrorLayer->sequence, args.name,
+ mirrorFrom->sequence);
}
- return addClientLayer(args.client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,
- false /* addToRoot */, nullptr /* outTransformHint */);
+ return addClientLayer(args.client, outResult.handle, mirrorLayer /* layer */,
+ nullptr /* parent */, false /* addToRoot */,
+ nullptr /* outTransformHint */);
}
status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args,
- sp<IBinder>* outHandle, int32_t* outLayerId) {
+ gui::CreateSurfaceResult& outResult) {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid != AID_ROOT && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != AID_SHELL) {
@@ -4625,9 +4418,10 @@
layerStack = display->getLayerStack();
LayerCreationArgs mirrorArgs = args;
mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill;
- result = createEffectLayer(mirrorArgs, outHandle, &rootMirrorLayer);
- *outLayerId = rootMirrorLayer->sequence;
- result |= addClientLayer(args.client, *outHandle, rootMirrorLayer /* layer */,
+ result = createEffectLayer(mirrorArgs, &outResult.handle, &rootMirrorLayer);
+ outResult.layerId = rootMirrorLayer->sequence;
+ outResult.layerName = String16(rootMirrorLayer->getDebugName());
+ result |= addClientLayer(args.client, outResult.handle, rootMirrorLayer /* layer */,
nullptr /* parent */, true /* addToRoot */,
nullptr /* outTransformHint */);
}
@@ -4637,26 +4431,21 @@
}
if (mTransactionTracing) {
- mTransactionTracing->onLayerAdded((*outHandle)->localBinder(), *outLayerId, args.name,
- args.flags, -1 /* parentId */);
+ mTransactionTracing->onLayerAdded(outResult.handle->localBinder(), outResult.layerId,
+ args.name, args.flags, -1 /* parentId */);
}
{
std::scoped_lock<std::mutex> lock(mMirrorDisplayLock);
- mMirrorDisplays.emplace_back(layerStack, *outHandle, args.client);
+ mMirrorDisplays.emplace_back(layerStack, outResult.handle, args.client);
}
setTransactionFlags(eTransactionFlushNeeded);
return NO_ERROR;
}
-status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
- const sp<IBinder>& parentHandle, int32_t* outLayerId,
- const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
- ALOG_ASSERT(parentLayer == nullptr || parentHandle == nullptr,
- "Expected only one of parentLayer or parentHandle to be non-null. "
- "Programmer error?");
-
+status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, const sp<IBinder>& parentHandle,
+ gui::CreateSurfaceResult& outResult) {
status_t result = NO_ERROR;
sp<Layer> layer;
@@ -4668,11 +4457,11 @@
args.flags |= ISurfaceComposerClient::eNoColorFill;
FMT_FALLTHROUGH;
case ISurfaceComposerClient::eFXSurfaceEffect: {
- result = createBufferStateLayer(args, outHandle, &layer);
+ result = createBufferStateLayer(args, &outResult.handle, &layer);
std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter();
if (pendingBufferCounter) {
std::string counterName = layer->getPendingBufferCounterName();
- mBufferCountTracker.add((*outHandle)->localBinder(), counterName,
+ mBufferCountTracker.add(outResult.handle->localBinder(), counterName,
pendingBufferCounter);
}
} break;
@@ -4686,14 +4475,11 @@
}
bool addToRoot = args.addToRoot && callingThreadHasUnscopedSurfaceFlingerAccess();
- wp<Layer> parent(parentHandle != nullptr ? fromHandle(parentHandle) : parentLayer);
+ wp<Layer> parent = fromHandle(parentHandle);
if (parentHandle != nullptr && parent == nullptr) {
ALOGE("Invalid parent handle %p.", parentHandle.get());
addToRoot = false;
}
- if (parentLayer != nullptr) {
- addToRoot = false;
- }
int parentId = -1;
// We can safely promote the layer in binder thread because we have a strong reference
@@ -4703,16 +4489,20 @@
parentId = parentSp->getSequence();
}
if (mTransactionTracing) {
- mTransactionTracing->onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
- args.flags, parentId);
+ mTransactionTracing->onLayerAdded(outResult.handle->localBinder(), layer->sequence,
+ args.name, args.flags, parentId);
}
- result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint);
+ uint32_t outTransformHint;
+ result = addClientLayer(args.client, outResult.handle, layer, parent, addToRoot,
+ &outTransformHint);
if (result != NO_ERROR) {
return result;
}
- *outLayerId = layer->sequence;
+ outResult.transformHint = static_cast<int32_t>(outTransformHint);
+ outResult.layerId = layer->sequence;
+ outResult.layerName = String16(layer->getDebugName());
return result;
}
@@ -4803,11 +4593,12 @@
return;
}
+ const bool isActiveDisplay = displayId == mActiveDisplayId;
const bool isInternalDisplay = mPhysicalDisplays.get(displayId)
.transform(&PhysicalDisplay::isInternal)
.value_or(false);
- const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
+ const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayId);
if (isInternalDisplay && activeDisplay != display && activeDisplay &&
activeDisplay->isPoweredOn()) {
ALOGW("Trying to change power mode on non active display while the active display is ON");
@@ -4815,9 +4606,6 @@
display->setPowerMode(mode);
- if (mInterceptor->isEnabled()) {
- mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
- }
const auto refreshRate = display->refreshRateConfigs().getActiveMode().getFps();
if (*currentMode == hal::PowerMode::OFF) {
// Turn on the display
@@ -4833,7 +4621,7 @@
ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
}
getHwComposer().setPowerMode(displayId, mode);
- if (isDisplayActiveLocked(display) && mode != hal::PowerMode::DOZE_SUSPEND) {
+ if (isActiveDisplay && mode != hal::PowerMode::DOZE_SUSPEND) {
setHWCVsyncEnabled(displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, refreshRate);
@@ -4849,7 +4637,7 @@
if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
}
- if (isDisplayActiveLocked(display) && *currentMode != hal::PowerMode::DOZE_SUSPEND) {
+ if (isActiveDisplay && *currentMode != hal::PowerMode::DOZE_SUSPEND) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
@@ -4863,7 +4651,7 @@
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (isDisplayActiveLocked(display) && *currentMode == hal::PowerMode::DOZE_SUSPEND) {
+ if (isActiveDisplay && *currentMode == hal::PowerMode::DOZE_SUSPEND) {
ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
mVisibleRegionsDirty = true;
scheduleRepaint();
@@ -4872,7 +4660,7 @@
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
- if (isDisplayActiveLocked(display)) {
+ if (isActiveDisplay) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
@@ -4882,7 +4670,7 @@
getHwComposer().setPowerMode(displayId, mode);
}
- if (isDisplayActiveLocked(display)) {
+ if (isActiveDisplay) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerMode(mode);
@@ -5100,18 +4888,22 @@
}
void SurfaceFlinger::dumpDisplays(std::string& result) const {
+ utils::Dumper dumper{result};
+
for (const auto& [id, display] : mPhysicalDisplays) {
if (const auto device = getDisplayDeviceLocked(id)) {
- device->dump(result);
+ device->dump(dumper);
}
- display.snapshot().dump(result);
- result += '\n';
+
+ utils::Dumper::Indent indent(dumper);
+ display.snapshot().dump(dumper);
+ dumper.eol();
}
for (const auto& [token, display] : mDisplays) {
if (display->isVirtual()) {
- display->dump(result);
- result += '\n';
+ display->dump(dumper);
+ dumper.eol();
}
}
}
@@ -5167,28 +4959,24 @@
}
void SurfaceFlinger::dumpWideColorInfo(std::string& result) const {
- StringAppendF(&result, "Device has wide color built-in display: %d\n", hasWideColorDisplay);
+ StringAppendF(&result, "Device supports wide color: %d\n", mSupportsWideColor);
StringAppendF(&result, "Device uses color management: %d\n", useColorManagement);
StringAppendF(&result, "DisplayColorSetting: %s\n",
decodeDisplayColorSetting(mDisplayColorSetting).c_str());
// TODO: print out if wide-color mode is active or not
- for (const auto& [token, display] : mDisplays) {
- const auto displayId = PhysicalDisplayId::tryCast(display->getId());
- if (!displayId) {
- continue;
- }
-
- StringAppendF(&result, "Display %s color modes:\n", to_string(*displayId).c_str());
- std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
- for (auto&& mode : modes) {
+ for (const auto& [id, display] : mPhysicalDisplays) {
+ StringAppendF(&result, "Display %s color modes:\n", to_string(id).c_str());
+ for (const auto mode : display.snapshot().colorModes()) {
StringAppendF(&result, " %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
- ColorMode currentMode = display->getCompositionDisplay()->getState().colorMode;
- StringAppendF(&result, " Current color mode: %s (%d)\n",
- decodeColorMode(currentMode).c_str(), currentMode);
+ if (const auto display = getDisplayDeviceLocked(id)) {
+ ui::ColorMode currentMode = display->getCompositionDisplay()->getState().colorMode;
+ StringAppendF(&result, " Current color mode: %s (%d)\n",
+ decodeColorMode(currentMode).c_str(), currentMode);
+ }
}
result.append("\n");
}
@@ -5268,7 +5056,7 @@
}
StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(),
- (isDisplayActiveLocked(display) ? "active" : "inactive"));
+ displayId == mActiveDisplayId ? "active" : "inactive");
Layer::miniDumpHeader(result);
const DisplayDevice& ref = *display;
@@ -5707,17 +5495,8 @@
mScheduler->setDuration(mSfConnectionHandle, std::chrono::nanoseconds(n), 0ns);
return NO_ERROR;
}
- case 1020: { // Layer updates interceptor
- n = data.readInt32();
- if (n) {
- ALOGV("Interceptor enabled");
- mInterceptor->enable(mDrawingState.layersSortedByZ, mDrawingState.displays);
- }
- else{
- ALOGV("Interceptor disabled");
- mInterceptor->disable();
- }
- return NO_ERROR;
+ case 1020: { // Unused
+ return NAME_NOT_FOUND;
}
case 1021: { // Disable HWC virtual displays
const bool enable = data.readInt32() != 0;
@@ -5732,12 +5511,11 @@
updateColorMatrixLocked();
return NO_ERROR;
}
- case 1023: { // Set native mode
- int32_t colorMode;
-
+ case 1023: { // Set color mode.
mDisplayColorSetting = static_cast<DisplayColorSetting>(data.readInt32());
- if (data.readInt32(&colorMode) == NO_ERROR) {
- mForceColorMode = static_cast<ColorMode>(colorMode);
+
+ if (int32_t colorMode; data.readInt32(&colorMode) == NO_ERROR) {
+ mForceColorMode = static_cast<ui::ColorMode>(colorMode);
}
scheduleRepaint();
return NO_ERROR;
@@ -5910,7 +5688,7 @@
case 1036: {
if (data.readInt32() > 0) { // turn on
return mScheduler
- ->schedule([this] {
+ ->schedule([this]() FTL_FAKE_GUARD(kMainThreadContext) {
const auto display =
FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
@@ -5920,24 +5698,21 @@
// defaultMode. The defaultMode doesn't matter for the override
// policy though, since we set allowGroupSwitching to true, so it's
// not a problem.
- scheduler::RefreshRateConfigs::Policy overridePolicy;
+ scheduler::RefreshRateConfigs::OverridePolicy overridePolicy;
overridePolicy.defaultMode = display->refreshRateConfigs()
.getDisplayManagerPolicy()
.defaultMode;
overridePolicy.allowGroupSwitching = true;
- constexpr bool kOverridePolicy = true;
- return setDesiredDisplayModeSpecsInternal(display, overridePolicy,
- kOverridePolicy);
+ return setDesiredDisplayModeSpecsInternal(display, overridePolicy);
})
.get();
} else { // turn off
return mScheduler
- ->schedule([this] {
+ ->schedule([this]() FTL_FAKE_GUARD(kMainThreadContext) {
const auto display =
FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
- constexpr bool kOverridePolicy = true;
- return setDesiredDisplayModeSpecsInternal(display, {},
- kOverridePolicy);
+ return setDesiredDisplayModeSpecsInternal(
+ display, scheduler::RefreshRateConfigs::NoOverridePolicy{});
})
.get();
}
@@ -6166,18 +5941,6 @@
const int mApi;
};
-static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) {
- switch (colorMode) {
- case ColorMode::DISPLAY_P3:
- case ColorMode::BT2100_PQ:
- case ColorMode::BT2100_HLG:
- case ColorMode::DISPLAY_BT2020:
- return Dataspace::DISPLAY_P3;
- default:
- return Dataspace::V0_SRGB;
- }
-}
-
static bool hasCaptureBlackoutContentPermission() {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
@@ -6289,15 +6052,11 @@
reqSize = display->getLayerStackSpaceRect().getSize();
}
- // The dataspace is depended on the color mode of display, that could use non-native mode
- // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes,
- // and failed if display is not in native mode. This provide a way to force using native
- // colors when capture.
- dataspace = args.dataspace;
- if (dataspace == ui::Dataspace::UNKNOWN) {
- const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
- dataspace = pickDataspaceFromColorMode(colorMode);
- }
+ // Allow the caller to specify a dataspace regardless of the display's color mode, e.g. if
+ // it wants sRGB regardless of the display's wide color mode.
+ dataspace = args.dataspace == ui::Dataspace::UNKNOWN
+ ? ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode)
+ : args.dataspace;
}
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
@@ -6332,9 +6091,7 @@
displayWeak = display;
layerStack = display->getLayerStack();
size = display->getLayerStackSpaceRect().getSize();
-
- dataspace =
- pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
+ dataspace = ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode);
}
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
@@ -6610,7 +6367,7 @@
auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance;
auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance;
- if ((dataspace == ui::Dataspace::UNKNOWN) && (parent != nullptr)) {
+ if (dataspace == ui::Dataspace::UNKNOWN && parent) {
Mutex::Autolock lock(mStateLock);
auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
return display.getLayerStack() == layerStack;
@@ -6620,8 +6377,7 @@
display = getDefaultDisplayDeviceLocked();
}
- const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
- dataspace = pickDataspaceFromColorMode(colorMode);
+ dataspace = ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode);
renderIntent = display->getCompositionDisplay()->getState().renderIntent;
sdrWhitePointNits = display->getCompositionDisplay()->getState().sdrWhitePointNits;
displayBrightnessNits = display->getCompositionDisplay()->getState().displayBrightnessNits;
@@ -6795,7 +6551,9 @@
status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
const sp<DisplayDevice>& display,
- const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
+ const scheduler::RefreshRateConfigs::PolicyVariant& policy) {
+ const auto displayId = display->getPhysicalId();
+
Mutex::Autolock lock(mStateLock);
if (mDebugDisplayModeSetByBackdoor) {
@@ -6803,31 +6561,31 @@
return NO_ERROR;
}
- const status_t setPolicyResult = display->setRefreshRatePolicy(policy, overridePolicy);
- if (setPolicyResult < 0) {
- return BAD_VALUE;
- }
- if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) {
- return NO_ERROR;
+ auto& configs = display->refreshRateConfigs();
+ using SetPolicyResult = scheduler::RefreshRateConfigs::SetPolicyResult;
+
+ switch (configs.setPolicy(policy)) {
+ case SetPolicyResult::Invalid:
+ return BAD_VALUE;
+ case SetPolicyResult::Unchanged:
+ return NO_ERROR;
+ case SetPolicyResult::Changed:
+ break;
}
- const scheduler::RefreshRateConfigs::Policy currentPolicy =
- display->refreshRateConfigs().getCurrentPolicy();
-
+ const scheduler::RefreshRateConfigs::Policy currentPolicy = configs.getCurrentPolicy();
ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str());
// TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
// be depending in this callback.
- const auto activeModePtr = display->refreshRateConfigs().getActiveModePtr();
- if (isDisplayActiveLocked(display)) {
+ if (const auto activeModePtr = configs.getActiveModePtr(); displayId == mActiveDisplayId) {
mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr);
toggleKernelIdleTimer();
} else {
mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr);
}
- auto preferredModeOpt =
- getPreferredDisplayMode(display->getPhysicalId(), currentPolicy.defaultMode);
+ auto preferredModeOpt = getPreferredDisplayMode(displayId, currentPolicy.defaultMode);
if (!preferredModeOpt) {
ALOGE("%s: Preferred mode is unknown", __func__);
return NAME_NOT_FOUND;
@@ -6839,7 +6597,7 @@
ALOGV("Switching to Scheduler preferred mode %d (%s)", preferredModeId.value(),
to_string(preferredMode->getFps()).c_str());
- if (!display->refreshRateConfigs().isModeAllowed(preferredModeId)) {
+ if (!configs.isModeAllowed(preferredModeId)) {
ALOGE("%s: Preferred mode %d is disallowed", __func__, preferredModeId.value());
return INVALID_OPERATION;
}
@@ -6858,7 +6616,7 @@
return BAD_VALUE;
}
- auto future = mScheduler->schedule([=]() -> status_t {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(kMainThreadContext) -> status_t {
const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
if (!display) {
ALOGE("Attempt to set desired display modes for invalid display token %p",
@@ -6868,16 +6626,15 @@
ALOGW("Attempt to set desired display modes for virtual display");
return INVALID_OPERATION;
} else {
- using Policy = scheduler::RefreshRateConfigs::Policy;
+ using Policy = scheduler::RefreshRateConfigs::DisplayManagerPolicy;
const Policy policy{DisplayModeId(defaultMode),
allowGroupSwitching,
{Fps::fromValue(primaryRefreshRateMin),
Fps::fromValue(primaryRefreshRateMax)},
{Fps::fromValue(appRequestRefreshRateMin),
Fps::fromValue(appRequestRefreshRateMax)}};
- constexpr bool kOverridePolicy = false;
- return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
+ return setDesiredDisplayModeSpecsInternal(display, policy);
}
});
@@ -7012,17 +6769,6 @@
}
}
-status_t SurfaceFlinger::addTransactionTraceListener(
- const sp<gui::ITransactionTraceListener>& listener) {
- if (!listener) {
- return BAD_VALUE;
- }
-
- mInterceptor->addTransactionTraceListener(listener);
-
- return NO_ERROR;
-}
-
int SurfaceFlinger::getGpuContextPriority() {
return getRenderEngine().getContextPriority();
}
@@ -7102,7 +6848,6 @@
if (mTransactionTracing) {
mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId.value);
}
- mInterceptor->saveSurfaceCreation(layer);
}
void SurfaceFlinger::sample() {
@@ -7121,7 +6866,7 @@
void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) {
ATRACE_CALL();
- if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
+ if (const auto display = getDisplayDeviceLocked(mActiveDisplayId)) {
display->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
}
@@ -7129,7 +6874,7 @@
ALOGE("%s: activeDisplay is null", __func__);
return;
}
- mActiveDisplayToken = activeDisplay->getDisplayToken();
+ mActiveDisplayId = activeDisplay->getPhysicalId();
activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
updateInternalDisplayVsyncLocked(activeDisplay);
mScheduler->setModeChangePending(false);
@@ -7244,6 +6989,31 @@
return true;
}
+void SurfaceFlinger::updateLayerMetadataSnapshot() {
+ LayerMetadata parentMetadata;
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ layer->updateMetadataSnapshot(parentMetadata);
+ }
+
+ std::unordered_set<Layer*> visited;
+ mDrawingState.traverse([&visited](Layer* layer) {
+ if (visited.find(layer) != visited.end()) {
+ return;
+ }
+
+ // If the layer isRelativeOf, then either it's relative metadata will be set
+ // recursively when updateRelativeMetadataSnapshot is called on its relative parent or
+ // it's relative parent has been deleted. Clear the layer's relativeLayerMetadata to ensure
+ // that layers with deleted relative parents don't hold stale relativeLayerMetadata.
+ if (layer->getDrawingState().isRelativeOf) {
+ layer->editLayerSnapshot()->relativeLayerMetadata = {};
+ return;
+ }
+
+ layer->updateRelativeMetadataSnapshot({}, visited);
+ });
+}
+
// gui::ISurfaceComposer
binder::Status SurfaceComposerAIDL::bootFinished() {
@@ -7594,30 +7364,6 @@
return binderStatusFromStatusT(status);
}
-binder::Status SurfaceComposerAIDL::enableVSyncInjections(bool enable) {
- if (!mFlinger->hasMockHwc()) {
- return binderStatusFromStatusT(PERMISSION_DENIED);
- }
-
- status_t status = checkAccessPermission();
- if (status == OK) {
- status = mFlinger->enableVSyncInjections(enable);
- }
- return binderStatusFromStatusT(status);
-}
-
-binder::Status SurfaceComposerAIDL::injectVSync(int64_t when) {
- if (!mFlinger->hasMockHwc()) {
- return binderStatusFromStatusT(PERMISSION_DENIED);
- }
-
- status_t status = checkAccessPermission();
- if (status == OK) {
- status = mFlinger->injectVSync(when);
- }
- return binderStatusFromStatusT(status);
-}
-
binder::Status SurfaceComposerAIDL::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) {
if (!outLayers) {
return binderStatusFromStatusT(UNEXPECTED_NULL);
@@ -7937,19 +7683,6 @@
return binderStatusFromStatusT(status);
}
-binder::Status SurfaceComposerAIDL::addTransactionTraceListener(
- const sp<gui::ITransactionTraceListener>& listener) {
- status_t status;
- IPCThreadState* ipc = IPCThreadState::self();
- const int uid = ipc->getCallingUid();
- if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
- status = mFlinger->addTransactionTraceListener(listener);
- } else {
- status = PERMISSION_DENIED;
- }
- return binderStatusFromStatusT(status);
-}
-
binder::Status SurfaceComposerAIDL::getGpuContextPriority(int32_t* outPriority) {
*outPriority = mFlinger->getGpuContextPriority();
return binder::Status::ok();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 163c1fd..0f8ac98 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -57,7 +57,6 @@
#include <scheduler/Time.h>
#include <ui/FenceResult.h>
-#include "ClientCache.h"
#include "Display/DisplayMap.h"
#include "Display/PhysicalDisplay.h"
#include "DisplayDevice.h"
@@ -66,19 +65,17 @@
#include "DisplayIdGenerator.h"
#include "Effects/Daltonizer.h"
#include "FlagManager.h"
-#include "FrameTracker.h"
#include "LayerVector.h"
-#include "LocklessQueue.h"
#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/VsyncModulator.h"
#include "SurfaceFlingerFactory.h"
#include "ThreadContext.h"
-#include "TracedOrdinal.h"
#include "Tracing/LayerTracing.h"
#include "Tracing/TransactionTracing.h"
#include "TransactionCallbackInvoker.h"
+#include "TransactionHandler.h"
#include "TransactionState.h"
#include <atomic>
@@ -214,10 +211,6 @@
static uint32_t maxGraphicsWidth;
static uint32_t maxGraphicsHeight;
- // Indicate if a device has wide color gamut display. This is typically
- // found on devices with wide color gamut (e.g. Display-P3) display.
- static bool hasWideColorDisplay;
-
// Indicate if device wants color management on its display.
static const constexpr bool useColorManagement = true;
@@ -341,6 +334,7 @@
friend class RegionSamplingThread;
friend class LayerRenderArea;
friend class LayerTracing;
+ friend class SurfaceComposerAIDL;
// For unit tests
friend class TestableSurfaceFlinger;
@@ -537,8 +531,6 @@
status_t overrideHdrTypes(const sp<IBinder>& displayToken,
const std::vector<ui::Hdr>& hdrTypes);
status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success);
- status_t enableVSyncInjections(bool enable);
- status_t injectVSync(nsecs_t when);
status_t getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers);
status_t getColorManagement(bool* outGetColorManagement) const;
status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
@@ -595,8 +587,6 @@
status_t setOverrideFrameRate(uid_t uid, float frameRate);
- status_t addTransactionTraceListener(const sp<gui::ITransactionTraceListener>& listener);
-
int getGpuContextPriority();
status_t getMaxAcquiredBufferCount(int* buffers) const;
@@ -609,7 +599,7 @@
void binderDied(const wp<IBinder>& who) override;
// HWC2::ComposerCallback overrides:
- void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp,
+ void onComposerHalVsync(hal::HWDisplayId, nsecs_t timestamp,
std::optional<hal::VsyncPeriodNanos>) override;
void onComposerHalHotplug(hal::HWDisplayId, hal::Connection) override;
void onComposerHalRefresh(hal::HWDisplayId) override;
@@ -638,8 +628,8 @@
// Toggles hardware VSYNC by calling into HWC.
void setVsyncEnabled(bool) override;
- // Sets the desired display mode if allowed by policy.
- void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override;
+ // Sets the desired display mode per display if allowed by policy .
+ void requestDisplayModes(std::vector<scheduler::DisplayModeConfig>) override;
// Called when kernel idle timer has expired. Used to update the refresh rate overlay.
void kernelTimerChanged(bool expired) override;
// Called when the frame rate override list changed to trigger an event.
@@ -685,11 +675,9 @@
DisplayModeId defaultModeId) const
REQUIRES(mStateLock);
- // Sets the desired display mode specs.
- status_t setDesiredDisplayModeSpecsInternal(
- const sp<DisplayDevice>& display,
- const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
- EXCLUDES(mStateLock);
+ status_t setDesiredDisplayModeSpecsInternal(const sp<DisplayDevice>&,
+ const scheduler::RefreshRateConfigs::PolicyVariant&)
+ EXCLUDES(mStateLock) REQUIRES(kMainThreadContext);
void commitTransactions() EXCLUDES(mStateLock) REQUIRES(kMainThreadContext);
void commitTransactionsLocked(uint32_t transactionFlags)
@@ -700,6 +688,7 @@
bool latchBuffers();
void updateLayerGeometry();
+ void updateLayerMetadataSnapshot();
void updateInputFlinger();
void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
@@ -729,11 +718,13 @@
bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext);
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
-
- int flushPendingTransactionQueues(
- std::vector<TransactionState>& transactions,
- std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
- bool tryApplyUnsignaled) REQUIRES(mStateLock) REQUIRES(kMainThreadContext);
+ void addTransactionReadyFilters();
+ TransactionHandler::TransactionReadiness transactionReadyTimelineCheck(
+ const TransactionHandler::TransactionFlushState& flushState)
+ REQUIRES(kMainThreadContext);
+ TransactionHandler::TransactionReadiness transactionReadyBufferCheck(
+ const TransactionHandler::TransactionFlushState& flushState)
+ REQUIRES(kMainThreadContext);
uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&,
int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -751,23 +742,9 @@
void commitOffscreenLayers();
- enum class TransactionReadiness {
- NotReady,
- NotReadyBarrier,
- Ready,
- ReadyUnsignaled,
- };
- TransactionReadiness transactionIsReadyToBeApplied(
- TransactionState&, const FrameTimelineInfo&, bool isAutoTimestamp,
- TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>&,
- const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>&
- bufferLayersReadyToPresent,
- size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock)
- REQUIRES(kMainThreadContext);
-
static LatchUnsignaledConfig getLatchUnsignaledConfig();
bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates,
- size_t totalTXapplied) const;
+ bool firstTransaction) const;
bool applyTransactions(std::vector<TransactionState>& transactions, VsyncId)
REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
@@ -778,10 +755,8 @@
/*
* Layer management
*/
- status_t createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
- const sp<IBinder>& parentHandle, int32_t* outLayerId,
- const sp<Layer>& parentLayer = nullptr,
- uint32_t* outTransformHint = nullptr);
+ status_t createLayer(LayerCreationArgs& args, const sp<IBinder>& parentHandle,
+ gui::CreateSurfaceResult& outResult);
status_t createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
sp<Layer>* outLayer);
@@ -790,10 +765,10 @@
sp<Layer>* outLayer);
status_t mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
- sp<IBinder>* outHandle, int32_t* outLayerId);
+ gui::CreateSurfaceResult& outResult);
status_t mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args,
- sp<IBinder>* outHandle, int32_t* outLayerId);
+ gui::CreateSurfaceResult& outResult);
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
@@ -841,10 +816,6 @@
void initializeDisplays();
void onInitializeDisplays() REQUIRES(mStateLock, kMainThreadContext);
- bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) {
- return display->getDisplayToken() == mActiveDisplayToken;
- }
-
sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const
REQUIRES(mStateLock) {
return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(displayToken);
@@ -879,12 +850,12 @@
}
sp<DisplayDevice> getDefaultDisplayDeviceLocked() REQUIRES(mStateLock) {
- if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
+ if (const auto display = getDisplayDeviceLocked(mActiveDisplayId)) {
return display;
}
// The active display is outdated, so fall back to the primary display.
- mActiveDisplayToken.clear();
- return getDisplayDeviceLocked(getPrimaryDisplayTokenLocked());
+ mActiveDisplayId = getPrimaryDisplayIdLocked();
+ return getDisplayDeviceLocked(mActiveDisplayId);
}
sp<const DisplayDevice> getDefaultDisplayDevice() const EXCLUDES(mStateLock) {
@@ -1094,20 +1065,12 @@
status_t CheckTransactCodeCredentials(uint32_t code);
// Add transaction to the Transaction Queue
- void queueTransaction(TransactionState& state);
- void waitForSynchronousTransaction(const CountDownLatch& transactionCommittedSignal);
- void signalSynchronousTransactions(const uint32_t flag);
/*
* Generic Layer Metadata
*/
const std::unordered_map<std::string, uint32_t>& getGenericLayerMetadataKeyMap() const;
- /*
- * Misc
- */
- std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId) REQUIRES(mStateLock);
-
static int calculateMaxAcquiredBufferCount(Fps refreshRate,
std::chrono::nanoseconds presentLatency);
int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
@@ -1129,7 +1092,6 @@
mutable Mutex mStateLock;
State mCurrentState{LayerVector::StateSet::Current};
std::atomic<int32_t> mTransactionFlags = 0;
- std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
std::atomic<uint32_t> mUniqueTransactionId = 1;
SortedVector<sp<Layer>> mLayersPendingRemoval;
@@ -1177,6 +1139,9 @@
bool mSomeDataspaceChanged = false;
bool mForceTransactionDisplayChange = false;
+ // Set if LayerMetadata has changed since the last LayerMetadata snapshot.
+ bool mLayerMetadataSnapshotNeeded = false;
+
// Tracks layers that have pending frames which are candidates for being
// latched.
std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames;
@@ -1212,6 +1177,9 @@
display::PhysicalDisplays mPhysicalDisplays GUARDED_BY(mStateLock);
+ // The inner or outer display for foldables, assuming they have mutually exclusive power states.
+ PhysicalDisplayId mActiveDisplayId GUARDED_BY(mStateLock);
+
struct {
DisplayIdGenerator<GpuVirtualDisplayId> gpu;
std::optional<DisplayIdGenerator<HalVirtualDisplayId>> hal;
@@ -1225,7 +1193,6 @@
bool mLayerCachingEnabled = false;
bool mPropagateBackpressureClientComposition = false;
- sp<SurfaceInterceptor> mInterceptor;
LayerTracing mLayerTracing{*this};
bool mLayerTracingEnabled = false;
@@ -1256,10 +1223,6 @@
uint32_t mTexturePoolSize = 0;
std::vector<uint32_t> mTexturePool;
- std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
- mPendingTransactionQueues;
- LocklessQueue<TransactionState> mLocklessTransactionQueue;
- std::atomic<size_t> mPendingTransactionCount = 0;
std::atomic<size_t> mNumLayers = 0;
// to linkToDeath
@@ -1282,6 +1245,10 @@
// This property can be used to force SurfaceFlinger to always pick a certain color mode.
ui::ColorMode mForceColorMode = ui::ColorMode::NATIVE;
+ // Whether to enable wide color gamut (e.g. Display P3) for internal displays that support it.
+ // If false, wide color modes are filtered out for all internal displays.
+ bool mSupportsWideColor = false;
+
ui::Dataspace mDefaultCompositionDataspace;
ui::Dataspace mWideColorGamutCompositionDataspace;
ui::Dataspace mColorSpaceAgnosticDataspace;
@@ -1294,8 +1261,6 @@
const std::string mHwcServiceName;
- bool hasMockHwc() const { return mHwcServiceName == "mock"; }
-
/*
* Scheduler
*/
@@ -1397,8 +1362,6 @@
[](const auto& display) { return display.isRefreshRateOverlayEnabled(); });
}
- wp<IBinder> mActiveDisplayToken GUARDED_BY(mStateLock);
-
const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
FlagManager mFlagManager;
@@ -1415,9 +1378,7 @@
bool early = false;
} mPowerHintSessionMode;
- nsecs_t mAnimationTransactionTimeout = s2ns(5);
-
- friend class SurfaceComposerAIDL;
+ TransactionHandler mTransactionHandler;
};
class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
@@ -1470,8 +1431,6 @@
binder::Status overrideHdrTypes(const sp<IBinder>& display,
const std::vector<int32_t>& hdrTypes) override;
binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override;
- binder::Status enableVSyncInjections(bool enable) override;
- binder::Status injectVSync(int64_t when) override;
binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) override;
binder::Status getColorManagement(bool* outGetColorManagement) override;
binder::Status getCompositionPreference(gui::CompositionPreference* outPref) override;
@@ -1521,8 +1480,6 @@
const sp<IBinder>& displayToken,
std::optional<gui::DisplayDecorationSupport>* outSupport) override;
binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override;
- binder::Status addTransactionTraceListener(
- const sp<gui::ITransactionTraceListener>& listener) override;
binder::Status getGpuContextPriority(int32_t* outPriority) override;
binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override;
binder::Status addWindowInfosListener(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 3e30dcb..2f1f263 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -29,7 +29,6 @@
#include "StartPropertySetThread.h"
#include "SurfaceFlingerDefaultFactory.h"
#include "SurfaceFlingerProperties.h"
-#include "SurfaceInterceptor.h"
#include "DisplayHardware/ComposerHal.h"
#include "FrameTimeline/FrameTimeline.h"
@@ -54,10 +53,6 @@
}
}
-sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() {
- return sp<android::impl::SurfaceInterceptor>::make();
-}
-
sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
bool timestampPropertyValue) {
return sp<StartPropertySetThread>::make(timestampPropertyValue);
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 6fca402..447a02f 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -29,7 +29,6 @@
std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) override;
- sp<SurfaceInterceptor> createSurfaceInterceptor() override;
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 6d18ade..9c4d5c8 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -40,7 +40,6 @@
class Layer;
class StartPropertySetThread;
class SurfaceFlinger;
-class SurfaceInterceptor;
class TimeStats;
struct DisplayDeviceCreationArgs;
@@ -71,7 +70,6 @@
virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) = 0;
- virtual sp<SurfaceInterceptor> createSurfaceInterceptor() = 0;
virtual sp<StartPropertySetThread> createStartPropertySetThread(
bool timestampPropertyValue) = 0;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
deleted file mode 100644
index 6797aa6..0000000
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
- * 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 "SurfaceInterceptor"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "Layer.h"
-#include "SurfaceFlinger.h"
-#include "SurfaceInterceptor.h"
-
-#include <fstream>
-
-#include <android-base/file.h>
-#include <log/log.h>
-#include <utils/Trace.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-// TODO(marissaw): add new layer state values to SurfaceInterceptor
-
-SurfaceInterceptor::~SurfaceInterceptor() = default;
-
-namespace impl {
-
-void SurfaceInterceptor::addTransactionTraceListener(
- const sp<gui::ITransactionTraceListener>& listener) {
- sp<IBinder> asBinder = IInterface::asBinder(listener);
-
- std::scoped_lock lock(mListenersMutex);
-
- asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
-
- listener->onToggled(mEnabled); // notifies of current state
-
- mTraceToggledListeners.emplace(asBinder, listener);
-}
-
-void SurfaceInterceptor::binderDied(const wp<IBinder>& who) {
- std::scoped_lock lock(mListenersMutex);
- mTraceToggledListeners.erase(who);
-}
-
-void SurfaceInterceptor::enable(const SortedVector<sp<Layer>>& layers,
- const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays)
-{
- if (mEnabled) {
- return;
- }
- ATRACE_CALL();
- {
- std::scoped_lock lock(mListenersMutex);
- for (const auto& [_, listener] : mTraceToggledListeners) {
- listener->onToggled(true);
- }
- }
- mEnabled = true;
- std::scoped_lock<std::mutex> protoGuard(mTraceMutex);
- saveExistingDisplaysLocked(displays);
- saveExistingSurfacesLocked(layers);
-}
-
-void SurfaceInterceptor::disable() {
- if (!mEnabled) {
- return;
- }
- ATRACE_CALL();
- {
- std::scoped_lock lock(mListenersMutex);
- for (const auto& [_, listener] : mTraceToggledListeners) {
- listener->onToggled(false);
- }
- }
- mEnabled = false;
- std::scoped_lock<std::mutex> protoGuard(mTraceMutex);
- status_t err(writeProtoFileLocked());
- ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
- ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
- mTrace.Clear();
-}
-
-bool SurfaceInterceptor::isEnabled() {
- return mEnabled;
-}
-
-void SurfaceInterceptor::saveExistingDisplaysLocked(
- const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays)
-{
- // Caveat: The initial snapshot does not capture the power mode of the existing displays
- ATRACE_CALL();
- for (size_t i = 0 ; i < displays.size() ; i++) {
- addDisplayCreationLocked(createTraceIncrementLocked(), displays[i]);
- addInitialDisplayStateLocked(createTraceIncrementLocked(), displays[i]);
- }
-}
-
-void SurfaceInterceptor::saveExistingSurfacesLocked(const SortedVector<sp<Layer>>& layers) {
- ATRACE_CALL();
- for (const auto& l : layers) {
- l->traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* layer) {
- addSurfaceCreationLocked(createTraceIncrementLocked(), sp<Layer>::fromExisting(layer));
- addInitialSurfaceStateLocked(createTraceIncrementLocked(),
- sp<Layer>::fromExisting(layer));
- });
- }
-}
-
-void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment,
- const sp<const Layer>& layer)
-{
- Transaction* transaction(increment->mutable_transaction());
- const uint32_t layerFlags = layer->getTransactionFlags();
- transaction->set_synchronous(layerFlags & BnSurfaceComposer::eSynchronous);
- transaction->set_animation(layerFlags & BnSurfaceComposer::eAnimation);
-
- const int32_t layerId(getLayerId(layer));
- addPositionLocked(transaction, layerId, layer->mDrawingState.transform.tx(),
- layer->mDrawingState.transform.ty());
- addDepthLocked(transaction, layerId, layer->mDrawingState.z);
- addAlphaLocked(transaction, layerId, layer->mDrawingState.color.a);
- addLayerStackLocked(transaction, layerId, layer->mDrawingState.layerStack);
- addCropLocked(transaction, layerId, layer->mDrawingState.crop);
- addCornerRadiusLocked(transaction, layerId, layer->mDrawingState.cornerRadius);
- addBackgroundBlurRadiusLocked(transaction, layerId, layer->mDrawingState.backgroundBlurRadius);
- addBlurRegionsLocked(transaction, layerId, layer->mDrawingState.blurRegions);
- addFlagsLocked(transaction, layerId, layer->mDrawingState.flags,
- layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque |
- layer_state_t::eLayerSecure);
- addReparentLocked(transaction, layerId, getLayerIdFromWeakRef(layer->mDrawingParent));
- addRelativeParentLocked(transaction, layerId,
- getLayerIdFromWeakRef(layer->mDrawingState.zOrderRelativeOf),
- layer->mDrawingState.z);
- addShadowRadiusLocked(transaction, layerId, layer->mDrawingState.shadowRadius);
- addTrustedOverlayLocked(transaction, layerId, layer->mDrawingState.isTrustedOverlay);
-}
-
-void SurfaceInterceptor::addInitialDisplayStateLocked(Increment* increment,
- const DisplayDeviceState& display)
-{
- Transaction* transaction(increment->mutable_transaction());
- transaction->set_synchronous(false);
- transaction->set_animation(false);
-
- addDisplaySurfaceLocked(transaction, display.sequenceId, display.surface);
- addDisplayLayerStackLocked(transaction, display.sequenceId, display.layerStack);
- addDisplayFlagsLocked(transaction, display.sequenceId, display.flags);
- addDisplaySizeLocked(transaction, display.sequenceId, display.width, display.height);
- addDisplayProjectionLocked(transaction, display.sequenceId, toRotationInt(display.orientation),
- display.layerStackSpaceRect, display.orientedDisplaySpaceRect);
-}
-
-status_t SurfaceInterceptor::writeProtoFileLocked() {
- ATRACE_CALL();
- std::string output;
-
- if (!mTrace.IsInitialized()) {
- return NOT_ENOUGH_DATA;
- }
- if (!mTrace.SerializeToString(&output)) {
- return PERMISSION_DENIED;
- }
- if (!android::base::WriteStringToFile(output, mOutputFileName, true)) {
- return PERMISSION_DENIED;
- }
-
- return NO_ERROR;
-}
-
-const sp<const Layer> SurfaceInterceptor::getLayer(const wp<IBinder>& weakHandle) const {
- sp<IBinder> handle = weakHandle.promote();
- return Layer::fromHandle(handle).promote();
-}
-
-int32_t SurfaceInterceptor::getLayerId(const sp<const Layer>& layer) const {
- return layer->sequence;
-}
-
-int32_t SurfaceInterceptor::getLayerIdFromWeakRef(const wp<const Layer>& layer) const {
- if (layer == nullptr) {
- return -1;
- }
- auto strongLayer = layer.promote();
- return strongLayer == nullptr ? -1 : getLayerId(strongLayer);
-}
-
-int32_t SurfaceInterceptor::getLayerIdFromHandle(const sp<IBinder>& handle) const {
- if (handle == nullptr) {
- return -1;
- }
- const sp<const Layer> layer = Layer::fromHandle(handle).promote();
- return layer == nullptr ? -1 : getLayerId(layer);
-}
-
-Increment* SurfaceInterceptor::createTraceIncrementLocked() {
- Increment* increment(mTrace.add_increment());
- increment->set_time_stamp(elapsedRealtimeNano());
- return increment;
-}
-
-SurfaceChange* SurfaceInterceptor::createSurfaceChangeLocked(Transaction* transaction,
- int32_t layerId)
-{
- SurfaceChange* change(transaction->add_surface_change());
- change->set_id(layerId);
- return change;
-}
-
-DisplayChange* SurfaceInterceptor::createDisplayChangeLocked(Transaction* transaction,
- int32_t sequenceId)
-{
- DisplayChange* dispChange(transaction->add_display_change());
- dispChange->set_id(sequenceId);
- return dispChange;
-}
-
-void SurfaceInterceptor::setProtoRectLocked(Rectangle* protoRect, const Rect& rect) {
- protoRect->set_left(rect.left);
- protoRect->set_top(rect.top);
- protoRect->set_right(rect.right);
- protoRect->set_bottom(rect.bottom);
-}
-
-void SurfaceInterceptor::setTransactionOriginLocked(Transaction* transaction, int32_t pid,
- int32_t uid) {
- Origin* origin(transaction->mutable_origin());
- origin->set_pid(pid);
- origin->set_uid(uid);
-}
-
-void SurfaceInterceptor::addPositionLocked(Transaction* transaction, int32_t layerId,
- float x, float y)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- PositionChange* posChange(change->mutable_position());
- posChange->set_x(x);
- posChange->set_y(y);
-}
-
-void SurfaceInterceptor::addDepthLocked(Transaction* transaction, int32_t layerId,
- uint32_t z)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- LayerChange* depthChange(change->mutable_layer());
- depthChange->set_layer(z);
-}
-
-void SurfaceInterceptor::addSizeLocked(Transaction* transaction, int32_t layerId, uint32_t w,
- uint32_t h)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- SizeChange* sizeChange(change->mutable_size());
- sizeChange->set_w(w);
- sizeChange->set_h(h);
-}
-
-void SurfaceInterceptor::addAlphaLocked(Transaction* transaction, int32_t layerId,
- float alpha)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- AlphaChange* alphaChange(change->mutable_alpha());
- alphaChange->set_alpha(alpha);
-}
-
-void SurfaceInterceptor::addMatrixLocked(Transaction* transaction, int32_t layerId,
- const layer_state_t::matrix22_t& matrix)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- MatrixChange* matrixChange(change->mutable_matrix());
- matrixChange->set_dsdx(matrix.dsdx);
- matrixChange->set_dtdx(matrix.dtdx);
- matrixChange->set_dsdy(matrix.dsdy);
- matrixChange->set_dtdy(matrix.dtdy);
-}
-
-void SurfaceInterceptor::addTransparentRegionLocked(Transaction* transaction,
- int32_t layerId, const Region& transRegion)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- TransparentRegionHintChange* transparentChange(change->mutable_transparent_region_hint());
-
- for (const auto& rect : transRegion) {
- Rectangle* protoRect(transparentChange->add_region());
- setProtoRectLocked(protoRect, rect);
- }
-}
-
-void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags,
- uint8_t mask) {
- // There can be multiple flags changed
- if (mask & layer_state_t::eLayerHidden) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- HiddenFlagChange* flagChange(change->mutable_hidden_flag());
- flagChange->set_hidden_flag(flags & layer_state_t::eLayerHidden);
- }
- if (mask & layer_state_t::eLayerOpaque) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- OpaqueFlagChange* flagChange(change->mutable_opaque_flag());
- flagChange->set_opaque_flag(flags & layer_state_t::eLayerOpaque);
- }
- if (mask & layer_state_t::eLayerSecure) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- SecureFlagChange* flagChange(change->mutable_secure_flag());
- flagChange->set_secure_flag(flags & layer_state_t::eLayerSecure);
- }
-}
-
-void SurfaceInterceptor::addLayerStackLocked(Transaction* transaction, int32_t layerId,
- ui::LayerStack layerStack) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- LayerStackChange* layerStackChange(change->mutable_layer_stack());
- layerStackChange->set_layer_stack(layerStack.id);
-}
-
-void SurfaceInterceptor::addCropLocked(Transaction* transaction, int32_t layerId,
- const Rect& rect)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- CropChange* cropChange(change->mutable_crop());
- Rectangle* protoRect(cropChange->mutable_rectangle());
- setProtoRectLocked(protoRect, rect);
-}
-
-void SurfaceInterceptor::addCornerRadiusLocked(Transaction* transaction, int32_t layerId,
- float cornerRadius)
-{
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- CornerRadiusChange* cornerRadiusChange(change->mutable_corner_radius());
- cornerRadiusChange->set_corner_radius(cornerRadius);
-}
-
-void SurfaceInterceptor::addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
- int32_t backgroundBlurRadius) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- BackgroundBlurRadiusChange* blurRadiusChange(change->mutable_background_blur_radius());
- blurRadiusChange->set_background_blur_radius(backgroundBlurRadius);
-}
-
-void SurfaceInterceptor::addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
- const std::vector<BlurRegion>& blurRegions) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- BlurRegionsChange* blurRegionsChange(change->mutable_blur_regions());
- for (const auto blurRegion : blurRegions) {
- const auto blurRegionChange = blurRegionsChange->add_blur_regions();
- blurRegionChange->set_blur_radius(blurRegion.blurRadius);
- blurRegionChange->set_corner_radius_tl(blurRegion.cornerRadiusTL);
- blurRegionChange->set_corner_radius_tr(blurRegion.cornerRadiusTR);
- blurRegionChange->set_corner_radius_bl(blurRegion.cornerRadiusBL);
- blurRegionChange->set_corner_radius_br(blurRegion.cornerRadiusBR);
- blurRegionChange->set_alpha(blurRegion.alpha);
- blurRegionChange->set_left(blurRegion.left);
- blurRegionChange->set_top(blurRegion.top);
- blurRegionChange->set_right(blurRegion.right);
- blurRegionChange->set_bottom(blurRegion.bottom);
- }
-}
-
-void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId,
- int32_t parentId) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- ReparentChange* overrideChange(change->mutable_reparent());
- overrideChange->set_parent_id(parentId);
-}
-
-void SurfaceInterceptor::addRelativeParentLocked(Transaction* transaction, int32_t layerId,
- int32_t parentId, int z) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- RelativeParentChange* overrideChange(change->mutable_relative_parent());
- overrideChange->set_relative_parent_id(parentId);
- overrideChange->set_z(z);
-}
-
-void SurfaceInterceptor::addShadowRadiusLocked(Transaction* transaction, int32_t layerId,
- float shadowRadius) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- ShadowRadiusChange* overrideChange(change->mutable_shadow_radius());
- overrideChange->set_radius(shadowRadius);
-}
-
-void SurfaceInterceptor::addTrustedOverlayLocked(Transaction* transaction, int32_t layerId,
- bool isTrustedOverlay) {
- SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
- TrustedOverlayChange* overrideChange(change->mutable_trusted_overlay());
- overrideChange->set_is_trusted_overlay(isTrustedOverlay);
-}
-
-void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction,
- const layer_state_t& state)
-{
- const sp<const Layer> layer(getLayer(state.surface));
- if (layer == nullptr) {
- ALOGE("An existing layer could not be retrieved with the surface "
- "from the layer_state_t surface in the update transaction");
- return;
- }
-
- const int32_t layerId(getLayerId(layer));
-
- if (state.what & layer_state_t::ePositionChanged) {
- addPositionLocked(transaction, layerId, state.x, state.y);
- }
- if (state.what & layer_state_t::eLayerChanged) {
- addDepthLocked(transaction, layerId, state.z);
- }
- if (state.what & layer_state_t::eAlphaChanged) {
- addAlphaLocked(transaction, layerId, state.alpha);
- }
- if (state.what & layer_state_t::eMatrixChanged) {
- addMatrixLocked(transaction, layerId, state.matrix);
- }
- if (state.what & layer_state_t::eTransparentRegionChanged) {
- addTransparentRegionLocked(transaction, layerId, state.transparentRegion);
- }
- if (state.what & layer_state_t::eFlagsChanged) {
- addFlagsLocked(transaction, layerId, state.flags, state.mask);
- }
- if (state.what & layer_state_t::eLayerStackChanged) {
- addLayerStackLocked(transaction, layerId, state.layerStack);
- }
- if (state.what & layer_state_t::eCropChanged) {
- addCropLocked(transaction, layerId, state.crop);
- }
- if (state.what & layer_state_t::eCornerRadiusChanged) {
- addCornerRadiusLocked(transaction, layerId, state.cornerRadius);
- }
- if (state.what & layer_state_t::eBackgroundBlurRadiusChanged) {
- addBackgroundBlurRadiusLocked(transaction, layerId, state.backgroundBlurRadius);
- }
- if (state.what & layer_state_t::eBlurRegionsChanged) {
- addBlurRegionsLocked(transaction, layerId, state.blurRegions);
- }
- if (state.what & layer_state_t::eReparent) {
- auto parentHandle = (state.parentSurfaceControlForChild)
- ? state.parentSurfaceControlForChild->getHandle()
- : nullptr;
- addReparentLocked(transaction, layerId, getLayerIdFromHandle(parentHandle));
- }
- if (state.what & layer_state_t::eRelativeLayerChanged) {
- addRelativeParentLocked(transaction, layerId,
- getLayerIdFromHandle(
- state.relativeLayerSurfaceControl->getHandle()),
- state.z);
- }
- if (state.what & layer_state_t::eShadowRadiusChanged) {
- addShadowRadiusLocked(transaction, layerId, state.shadowRadius);
- }
- if (state.what & layer_state_t::eTrustedOverlayChanged) {
- addTrustedOverlayLocked(transaction, layerId, state.isTrustedOverlay);
- }
- if (state.what & layer_state_t::eStretchChanged) {
- ALOGW("SurfaceInterceptor not implemented for eStretchChanged");
- }
-}
-
-void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction,
- const DisplayState& state, int32_t sequenceId)
-{
- if (state.what & DisplayState::eSurfaceChanged) {
- addDisplaySurfaceLocked(transaction, sequenceId, state.surface);
- }
- if (state.what & DisplayState::eLayerStackChanged) {
- addDisplayLayerStackLocked(transaction, sequenceId, state.layerStack);
- }
- if (state.what & DisplayState::eFlagsChanged) {
- addDisplayFlagsLocked(transaction, sequenceId, state.flags);
- }
- if (state.what & DisplayState::eDisplaySizeChanged) {
- addDisplaySizeLocked(transaction, sequenceId, state.width, state.height);
- }
- if (state.what & DisplayState::eDisplayProjectionChanged) {
- addDisplayProjectionLocked(transaction, sequenceId, toRotationInt(state.orientation),
- state.layerStackSpaceRect, state.orientedDisplaySpaceRect);
- }
-}
-
-void SurfaceInterceptor::addTransactionLocked(
- Increment* increment, const Vector<ComposerState>& stateUpdates,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags, int originPid,
- int originUid, uint64_t transactionId) {
- Transaction* transaction(increment->mutable_transaction());
- transaction->set_synchronous(transactionFlags & BnSurfaceComposer::eSynchronous);
- transaction->set_animation(transactionFlags & BnSurfaceComposer::eAnimation);
- setTransactionOriginLocked(transaction, originPid, originUid);
- transaction->set_id(transactionId);
- for (const auto& compState: stateUpdates) {
- addSurfaceChangesLocked(transaction, compState.state);
- }
- for (const auto& disp: changedDisplays) {
- ssize_t dpyIdx = displays.indexOfKey(disp.token);
- if (dpyIdx >= 0) {
- const DisplayDeviceState& dispState(displays.valueAt(dpyIdx));
- addDisplayChangesLocked(transaction, disp, dispState.sequenceId);
- }
- }
-}
-
-void SurfaceInterceptor::addSurfaceCreationLocked(Increment* increment,
- const sp<const Layer>& layer)
-{
- SurfaceCreation* creation(increment->mutable_surface_creation());
- creation->set_id(getLayerId(layer));
- creation->set_name(layer->getName());
-}
-
-void SurfaceInterceptor::addSurfaceDeletionLocked(Increment* increment,
- const sp<const Layer>& layer)
-{
- SurfaceDeletion* deletion(increment->mutable_surface_deletion());
- deletion->set_id(getLayerId(layer));
-}
-
-void SurfaceInterceptor::addBufferUpdateLocked(Increment* increment, int32_t layerId,
- uint32_t width, uint32_t height, uint64_t frameNumber)
-{
- BufferUpdate* update(increment->mutable_buffer_update());
- update->set_id(layerId);
- update->set_w(width);
- update->set_h(height);
- update->set_frame_number(frameNumber);
-}
-
-void SurfaceInterceptor::addVSyncUpdateLocked(Increment* increment, nsecs_t timestamp) {
- VSyncEvent* event(increment->mutable_vsync_event());
- event->set_when(timestamp);
-}
-
-void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId,
- const sp<const IGraphicBufferProducer>& surface)
-{
- if (surface == nullptr) {
- return;
- }
- uint64_t bufferQueueId = 0;
- status_t err(surface->getUniqueId(&bufferQueueId));
- if (err == NO_ERROR) {
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
- DispSurfaceChange* surfaceChange(dispChange->mutable_surface());
- surfaceChange->set_buffer_queue_id(bufferQueueId);
- surfaceChange->set_buffer_queue_name(surface->getConsumerName().string());
- }
- else {
- ALOGE("invalid graphic buffer producer received while tracing a display change (%s)",
- strerror(-err));
- }
-}
-
-void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId,
- ui::LayerStack layerStack) {
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
- LayerStackChange* layerStackChange(dispChange->mutable_layer_stack());
- layerStackChange->set_layer_stack(layerStack.id);
-}
-
-void SurfaceInterceptor::addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId,
- uint32_t flags) {
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
- DisplayFlagsChange* flagsChange(dispChange->mutable_flags());
- flagsChange->set_flags(flags);
-}
-
-void SurfaceInterceptor::addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId,
- uint32_t w, uint32_t h)
-{
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
- SizeChange* sizeChange(dispChange->mutable_size());
- sizeChange->set_w(w);
- sizeChange->set_h(h);
-}
-
-void SurfaceInterceptor::addDisplayProjectionLocked(Transaction* transaction,
- int32_t sequenceId, int32_t orientation, const Rect& viewport, const Rect& frame)
-{
- DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
- ProjectionChange* projectionChange(dispChange->mutable_projection());
- projectionChange->set_orientation(orientation);
- Rectangle* viewportRect(projectionChange->mutable_viewport());
- setProtoRectLocked(viewportRect, viewport);
- Rectangle* frameRect(projectionChange->mutable_frame());
- setProtoRectLocked(frameRect, frame);
-}
-
-void SurfaceInterceptor::addDisplayCreationLocked(Increment* increment,
- const DisplayDeviceState& info)
-{
- DisplayCreation* creation(increment->mutable_display_creation());
- creation->set_id(info.sequenceId);
- creation->set_name(info.displayName);
- creation->set_is_secure(info.isSecure);
- if (info.physical) {
- creation->set_display_id(info.physical->id.value);
- }
-}
-
-void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t sequenceId) {
- DisplayDeletion* deletion(increment->mutable_display_deletion());
- deletion->set_id(sequenceId);
-}
-
-void SurfaceInterceptor::addPowerModeUpdateLocked(Increment* increment, int32_t sequenceId,
- int32_t mode)
-{
- PowerModeUpdate* powerModeUpdate(increment->mutable_power_mode_update());
- powerModeUpdate->set_id(sequenceId);
- powerModeUpdate->set_mode(mode);
-}
-
-void SurfaceInterceptor::saveTransaction(
- const Vector<ComposerState>& stateUpdates,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPid, int originUid,
- uint64_t transactionId) {
- if (!mEnabled || (stateUpdates.size() <= 0 && changedDisplays.size() <= 0)) {
- return;
- }
- ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addTransactionLocked(createTraceIncrementLocked(), stateUpdates, displays, changedDisplays,
- flags, originPid, originUid, transactionId);
-}
-
-void SurfaceInterceptor::saveSurfaceCreation(const sp<const Layer>& layer) {
- if (!mEnabled || layer == nullptr) {
- return;
- }
- ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addSurfaceCreationLocked(createTraceIncrementLocked(), layer);
-}
-
-void SurfaceInterceptor::saveSurfaceDeletion(const sp<const Layer>& layer) {
- if (!mEnabled || layer == nullptr) {
- return;
- }
- ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addSurfaceDeletionLocked(createTraceIncrementLocked(), layer);
-}
-
-/**
- * Here we pass the layer by ID instead of by sp<> since this is called without
- * holding the state-lock from a Binder thread. If we required the caller
- * to pass 'this' by sp<> the temporary sp<> constructed could end up
- * being the last reference and we might accidentally destroy the Layer
- * from this binder thread.
- */
-void SurfaceInterceptor::saveBufferUpdate(int32_t layerId, uint32_t width,
- uint32_t height, uint64_t frameNumber)
-{
- if (!mEnabled) {
- return;
- }
- ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addBufferUpdateLocked(createTraceIncrementLocked(), layerId, width, height, frameNumber);
-}
-
-void SurfaceInterceptor::saveVSyncEvent(nsecs_t timestamp) {
- if (!mEnabled) {
- return;
- }
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addVSyncUpdateLocked(createTraceIncrementLocked(), timestamp);
-}
-
-void SurfaceInterceptor::saveDisplayCreation(const DisplayDeviceState& info) {
- if (!mEnabled) {
- return;
- }
- ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addDisplayCreationLocked(createTraceIncrementLocked(), info);
-}
-
-void SurfaceInterceptor::saveDisplayDeletion(int32_t sequenceId) {
- if (!mEnabled) {
- return;
- }
- ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addDisplayDeletionLocked(createTraceIncrementLocked(), sequenceId);
-}
-
-void SurfaceInterceptor::savePowerModeUpdate(int32_t sequenceId, int32_t mode) {
- if (!mEnabled) {
- return;
- }
- ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addPowerModeUpdateLocked(createTraceIncrementLocked(), sequenceId, mode);
-}
-
-} // namespace impl
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
deleted file mode 100644
index 970c3e5..0000000
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_SURFACEINTERCEPTOR_H
-#define ANDROID_SURFACEINTERCEPTOR_H
-
-#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
-
-#include <mutex>
-
-#include <binder/IBinder.h>
-
-#include <gui/LayerState.h>
-
-#include <utils/KeyedVector.h>
-#include <utils/SortedVector.h>
-#include <utils/StrongPointer.h>
-#include <utils/Vector.h>
-
-#include "DisplayDevice.h"
-
-namespace android {
-
-class BufferItem;
-class Layer;
-class SurfaceFlinger;
-struct ComposerState;
-struct DisplayDeviceState;
-struct DisplayState;
-struct layer_state_t;
-using Transaction = surfaceflinger::Transaction;
-using Trace = surfaceflinger::Trace;
-using Rectangle = surfaceflinger::Rectangle;
-using SurfaceChange = surfaceflinger::SurfaceChange;
-using Increment = surfaceflinger::Increment;
-using DisplayChange = surfaceflinger::DisplayChange;
-
-constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope";
-
-class SurfaceInterceptor : public IBinder::DeathRecipient {
-public:
- virtual ~SurfaceInterceptor();
-
- // Both vectors are used to capture the current state of SF as the initial snapshot in the trace
- virtual void enable(const SortedVector<sp<Layer>>& layers,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays) = 0;
- virtual void disable() = 0;
- virtual bool isEnabled() = 0;
-
- virtual void addTransactionTraceListener(
- const sp<gui::ITransactionTraceListener>& listener) = 0;
- virtual void binderDied(const wp<IBinder>& who) = 0;
-
- // Intercept display and surface transactions
- virtual void saveTransaction(
- const Vector<ComposerState>& stateUpdates,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPid,
- int originUid, uint64_t transactionId) = 0;
-
- // Intercept surface data
- virtual void saveSurfaceCreation(const sp<const Layer>& layer) = 0;
- virtual void saveSurfaceDeletion(const sp<const Layer>& layer) = 0;
- virtual void saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height,
- uint64_t frameNumber) = 0;
-
- // Intercept display data
- virtual void saveDisplayCreation(const DisplayDeviceState& info) = 0;
- virtual void saveDisplayDeletion(int32_t sequenceId) = 0;
- virtual void savePowerModeUpdate(int32_t sequenceId, int32_t mode) = 0;
- virtual void saveVSyncEvent(nsecs_t timestamp) = 0;
-};
-
-namespace impl {
-
-/*
- * SurfaceInterceptor intercepts and stores incoming streams of window
- * properties on SurfaceFlinger.
- */
-class SurfaceInterceptor final : public android::SurfaceInterceptor {
-public:
- SurfaceInterceptor() = default;
- ~SurfaceInterceptor() override = default;
-
- // Both vectors are used to capture the current state of SF as the initial snapshot in the trace
- void enable(const SortedVector<sp<Layer>>& layers,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays) override;
- void disable() override;
- bool isEnabled() override;
-
- void addTransactionTraceListener(const sp<gui::ITransactionTraceListener>& listener) override;
- void binderDied(const wp<IBinder>& who) override;
-
- // Intercept display and surface transactions
- void saveTransaction(const Vector<ComposerState>& stateUpdates,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPid,
- int originUid, uint64_t transactionId) override;
-
- // Intercept surface data
- void saveSurfaceCreation(const sp<const Layer>& layer) override;
- void saveSurfaceDeletion(const sp<const Layer>& layer) override;
- void saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height,
- uint64_t frameNumber) override;
-
- // Intercept display data
- void saveDisplayCreation(const DisplayDeviceState& info) override;
- void saveDisplayDeletion(int32_t sequenceId) override;
- void savePowerModeUpdate(int32_t sequenceId, int32_t mode) override;
- void saveVSyncEvent(nsecs_t timestamp) override;
-
-private:
- // The creation increments of Surfaces and Displays do not contain enough information to capture
- // the initial state of each object, so a transaction with all of the missing properties is
- // performed at the initial snapshot for each display and surface.
- void saveExistingDisplaysLocked(
- const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays);
- void saveExistingSurfacesLocked(const SortedVector<sp<Layer>>& layers);
- void addInitialSurfaceStateLocked(Increment* increment, const sp<const Layer>& layer);
- void addInitialDisplayStateLocked(Increment* increment, const DisplayDeviceState& display);
-
- status_t writeProtoFileLocked();
- const sp<const Layer> getLayer(const wp<IBinder>& weakHandle) const;
- int32_t getLayerId(const sp<const Layer>& layer) const;
- int32_t getLayerIdFromWeakRef(const wp<const Layer>& layer) const;
- int32_t getLayerIdFromHandle(const sp<IBinder>& weakHandle) const;
-
- Increment* createTraceIncrementLocked();
- void addSurfaceCreationLocked(Increment* increment, const sp<const Layer>& layer);
- void addSurfaceDeletionLocked(Increment* increment, const sp<const Layer>& layer);
- void addBufferUpdateLocked(Increment* increment, int32_t layerId, uint32_t width,
- uint32_t height, uint64_t frameNumber);
- void addVSyncUpdateLocked(Increment* increment, nsecs_t timestamp);
- void addDisplayCreationLocked(Increment* increment, const DisplayDeviceState& info);
- void addDisplayDeletionLocked(Increment* increment, int32_t sequenceId);
- void addPowerModeUpdateLocked(Increment* increment, int32_t sequenceId, int32_t mode);
-
- // Add surface transactions to the trace
- SurfaceChange* createSurfaceChangeLocked(Transaction* transaction, int32_t layerId);
- void setProtoRectLocked(Rectangle* protoRect, const Rect& rect);
- void addPositionLocked(Transaction* transaction, int32_t layerId, float x, float y);
- void addDepthLocked(Transaction* transaction, int32_t layerId, uint32_t z);
- void addSizeLocked(Transaction* transaction, int32_t layerId, uint32_t w, uint32_t h);
- void addAlphaLocked(Transaction* transaction, int32_t layerId, float alpha);
- void addMatrixLocked(Transaction* transaction, int32_t layerId,
- const layer_state_t::matrix22_t& matrix);
- void addTransparentRegionLocked(Transaction* transaction, int32_t layerId,
- const Region& transRegion);
- void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags, uint8_t mask);
- void addLayerStackLocked(Transaction* transaction, int32_t layerId, ui::LayerStack);
- void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
- void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
- void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
- int32_t backgroundBlurRadius);
- void addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
- const std::vector<BlurRegion>& effectRegions);
- void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state);
- void addTransactionLocked(Increment* increment, const Vector<ComposerState>& stateUpdates,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays,
- uint32_t transactionFlags, int originPid, int originUid,
- uint64_t transactionId);
- void addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
- void addRelativeParentLocked(Transaction* transaction, int32_t layerId, int32_t parentId,
- int z);
- void addShadowRadiusLocked(Transaction* transaction, int32_t layerId, float shadowRadius);
- void addTrustedOverlayLocked(Transaction* transaction, int32_t layerId, bool isTrustedOverlay);
-
- // Add display transactions to the trace
- DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId);
- void addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId,
- const sp<const IGraphicBufferProducer>& surface);
- void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, ui::LayerStack);
- void addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, uint32_t flags);
- void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w,
- uint32_t h);
- void addDisplayProjectionLocked(Transaction* transaction, int32_t sequenceId,
- int32_t orientation, const Rect& viewport, const Rect& frame);
- void addDisplayChangesLocked(Transaction* transaction,
- const DisplayState& state, int32_t sequenceId);
-
- // Add transaction origin to trace
- void setTransactionOriginLocked(Transaction* transaction, int32_t pid, int32_t uid);
-
- bool mEnabled {false};
- std::string mOutputFileName {DEFAULT_FILENAME};
- std::mutex mTraceMutex {};
- Trace mTrace {};
- std::mutex mListenersMutex;
- std::map<wp<IBinder>, sp<gui::ITransactionTraceListener>> mTraceToggledListeners
- GUARDED_BY(mListenersMutex);
-};
-
-} // namespace impl
-
-} // namespace android
-
-#endif // ANDROID_SURFACEINTERCEPTOR_H
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index dcc529e..3418c82 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -111,7 +111,7 @@
}
if (layer.what & layer_state_t::eAlphaChanged) {
- proto.set_alpha(layer.alpha);
+ proto.set_alpha(layer.color.a);
}
if (layer.what & layer_state_t::eColorChanged) {
@@ -123,8 +123,8 @@
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::eBufferTransformChanged) {
+ proto.set_transform(layer.bufferTransform);
}
if (layer.what & layer_state_t::eTransformToDisplayInverseChanged) {
proto.set_transform_to_display_inverse(layer.transformToDisplayInverse);
@@ -395,7 +395,7 @@
}
if (proto.what() & layer_state_t::eAlphaChanged) {
- layer.alpha = proto.alpha();
+ layer.color.a = proto.alpha();
}
if (proto.what() & layer_state_t::eColorChanged) {
@@ -407,8 +407,8 @@
if (proto.what() & layer_state_t::eTransparentRegionChanged) {
LayerProtoHelper::readFromProto(proto.transparent_region(), layer.transparentRegion);
}
- if (proto.what() & layer_state_t::eTransformChanged) {
- layer.transform = proto.transform();
+ if (proto.what() & layer_state_t::eBufferTransformChanged) {
+ layer.bufferTransform = proto.transform();
}
if (proto.what() & layer_state_t::eTransformToDisplayInverseChanged) {
layer.transformToDisplayInverse = proto.transform_to_display_inverse();
@@ -452,7 +452,7 @@
layer.parentSurfaceControlForChild =
sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
- static_cast<int32_t>(layerId));
+ static_cast<int32_t>(layerId), "");
}
}
if (proto.what() & layer_state_t::eRelativeLayerChanged) {
@@ -463,7 +463,7 @@
layer.relativeLayerSurfaceControl =
sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
- static_cast<int32_t>(layerId));
+ static_cast<int32_t>(layerId), "");
}
layer.z = proto.z();
}
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index 872a901..2232bb9 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -15,6 +15,7 @@
*/
#pragma once
+#include <gui/fake/BufferData.h>
#include <layerproto/TransactionProto.h>
#include <utils/RefBase.h>
@@ -43,35 +44,6 @@
TracingLayerCreationArgs args;
};
-// Class which exposes buffer properties from BufferData without holding on to the actual buffer
-// handle.
-class BufferDataStub : public BufferData {
-public:
- BufferDataStub(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat,
- uint64_t outUsage)
- : mBufferId(bufferId),
- mWidth(width),
- mHeight(height),
- mPixelFormat(pixelFormat),
- mOutUsage(outUsage) {}
- bool hasBuffer() const override { return mBufferId != 0; }
- bool hasSameBuffer(const BufferData& other) const override {
- return getId() == other.getId() && frameNumber == other.frameNumber;
- }
- uint32_t getWidth() const override { return mWidth; }
- uint32_t getHeight() const override { return mHeight; }
- uint64_t getId() const override { return mBufferId; }
- PixelFormat getPixelFormat() const override { return mPixelFormat; }
- uint64_t getUsage() const override { return mOutUsage; }
-
-private:
- uint64_t mBufferId;
- uint32_t mWidth;
- uint32_t mHeight;
- int32_t mPixelFormat;
- uint64_t mOutUsage;
-};
-
class TransactionProtoParser {
public:
// Utility class to map handles to ids and buffers to buffer properties without pulling
@@ -87,7 +59,7 @@
virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
uint32_t height, int32_t pixelFormat,
uint64_t usage) const {
- return std::make_shared<BufferDataStub>(bufferId, width, height, pixelFormat, usage);
+ return std::make_shared<fake::BufferData>(bufferId, width, height, pixelFormat, usage);
}
virtual void getGraphicBufferPropertiesFromCache(client_cache_t /* cachedBuffer */,
uint64_t* /* outBufferId */,
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 8817178..d0364f2 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -47,10 +47,6 @@
return std::make_unique<scheduler::FakePhaseOffsets>();
}
- sp<SurfaceInterceptor> createSurfaceInterceptor() override {
- return sp<android::impl::SurfaceInterceptor>::make();
- }
-
sp<StartPropertySetThread> createStartPropertySetThread(
bool /* timestampPropertyValue */) override {
return sp<StartPropertySetThread>();
@@ -213,8 +209,7 @@
TracingLayerCreationArgs tracingArgs;
parser.fromProto(entry.added_layers(j), tracingArgs);
- sp<IBinder> outHandle;
- int32_t outLayerId;
+ gui::CreateSurfaceResult outResult;
LayerCreationArgs args(mFlinger.flinger(), nullptr /* client */, tracingArgs.name,
tracingArgs.flags, LayerMetadata());
args.sequence = std::make_optional<int32_t>(tracingArgs.layerId);
@@ -228,16 +223,15 @@
} else if (tracingArgs.parentId != -1) {
parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId);
}
- mFlinger.createLayer(args, &outHandle, parentHandle, &outLayerId,
- nullptr /* parentLayer */, nullptr /* outTransformHint */);
+ mFlinger.createLayer(args, parentHandle, outResult);
} else {
sp<IBinder> mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId);
- mFlinger.mirrorLayer(args, mirrorFromHandle, &outHandle, &outLayerId);
+ mFlinger.mirrorLayer(args, mirrorFromHandle, outResult);
}
- LOG_ALWAYS_FATAL_IF(outLayerId != tracingArgs.layerId,
+ LOG_ALWAYS_FATAL_IF(outResult.layerId != tracingArgs.layerId,
"Could not create layer expected:%d actual:%d", tracingArgs.layerId,
- outLayerId);
- dataMapper->mLayerHandles[tracingArgs.layerId] = outHandle;
+ outResult.layerId);
+ dataMapper->mLayerHandles[tracingArgs.layerId] = outResult.handle;
}
for (int j = 0; j < entry.transactions_size(); j++) {
diff --git a/services/surfaceflinger/TransactionHandler.cpp b/services/surfaceflinger/TransactionHandler.cpp
new file mode 100644
index 0000000..6c6a487
--- /dev/null
+++ b/services/surfaceflinger/TransactionHandler.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "TransactionHandler"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <cutils/trace.h>
+#include <utils/Log.h>
+
+#include "TransactionHandler.h"
+
+namespace android {
+
+void TransactionHandler::queueTransaction(TransactionState&& state) {
+ mLocklessTransactionQueue.push(std::move(state));
+ mPendingTransactionCount.fetch_add(1);
+ ATRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
+}
+
+std::vector<TransactionState> TransactionHandler::flushTransactions() {
+ while (!mLocklessTransactionQueue.isEmpty()) {
+ auto maybeTransaction = mLocklessTransactionQueue.pop();
+ if (!maybeTransaction.has_value()) {
+ break;
+ }
+ auto transaction = maybeTransaction.value();
+ mPendingTransactionQueues[transaction.applyToken].emplace(std::move(transaction));
+ }
+
+ // Collect transaction that are ready to be applied.
+ std::vector<TransactionState> transactions;
+ TransactionFlushState flushState;
+ flushState.queueProcessTime = systemTime();
+ // Transactions with a buffer pending on a barrier may be on a different applyToken
+ // than the transaction which satisfies our barrier. In fact this is the exact use case
+ // that the primitive is designed for. This means we may first process
+ // the barrier dependent transaction, determine it ineligible to complete
+ // and then satisfy in a later inner iteration of flushPendingTransactionQueues.
+ // The barrier dependent transaction was eligible to be presented in this frame
+ // but we would have prevented it without case. To fix this we continually
+ // loop through flushPendingTransactionQueues until we perform an iteration
+ // where the number of transactionsPendingBarrier doesn't change. This way
+ // we can continue to resolve dependency chains of barriers as far as possible.
+ int lastTransactionsPendingBarrier = 0;
+ int transactionsPendingBarrier = 0;
+ do {
+ lastTransactionsPendingBarrier = transactionsPendingBarrier;
+ // Collect transactions that are ready to be applied.
+ transactionsPendingBarrier = flushPendingTransactionQueues(transactions, flushState);
+ } while (lastTransactionsPendingBarrier != transactionsPendingBarrier);
+
+ mPendingTransactionCount.fetch_sub(transactions.size());
+ ATRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
+ return transactions;
+}
+
+TransactionHandler::TransactionReadiness TransactionHandler::applyFilters(
+ TransactionFlushState& flushState) {
+ auto ready = TransactionReadiness::Ready;
+ for (auto& filter : mTransactionReadyFilters) {
+ auto perFilterReady = filter(flushState);
+ switch (perFilterReady) {
+ case TransactionReadiness::NotReady:
+ case TransactionReadiness::NotReadyBarrier:
+ return perFilterReady;
+
+ case TransactionReadiness::ReadyUnsignaled:
+ case TransactionReadiness::ReadyUnsignaledSingle:
+ // If one of the filters allows latching an unsignaled buffer, latch this ready
+ // state.
+ ready = perFilterReady;
+ break;
+ case TransactionReadiness::Ready:
+ continue;
+ }
+ }
+ return ready;
+}
+
+int TransactionHandler::flushPendingTransactionQueues(std::vector<TransactionState>& transactions,
+ TransactionFlushState& flushState) {
+ int transactionsPendingBarrier = 0;
+ auto it = mPendingTransactionQueues.begin();
+ while (it != mPendingTransactionQueues.end()) {
+ auto& queue = it->second;
+ IBinder* queueToken = it->first.get();
+
+ // if we have already flushed a transaction with an unsignaled buffer then stop queue
+ // processing
+ if (std::find(flushState.queuesWithUnsignaledBuffers.begin(),
+ flushState.queuesWithUnsignaledBuffers.end(),
+ queueToken) != flushState.queuesWithUnsignaledBuffers.end()) {
+ continue;
+ }
+
+ while (!queue.empty()) {
+ auto& transaction = queue.front();
+ flushState.transaction = &transaction;
+ auto ready = applyFilters(flushState);
+ if (ready == TransactionReadiness::NotReadyBarrier) {
+ transactionsPendingBarrier++;
+ break;
+ } else if (ready == TransactionReadiness::NotReady) {
+ break;
+ }
+
+ // Transaction is ready move it from the pending queue.
+ flushState.firstTransaction = false;
+ removeFromStalledTransactions(transaction.id);
+ transactions.emplace_back(std::move(transaction));
+ queue.pop();
+
+ // If the buffer is unsignaled, then we don't want to signal other transactions using
+ // the buffer as a barrier.
+ auto& readyToApplyTransaction = transactions.back();
+ if (ready == TransactionReadiness::Ready) {
+ readyToApplyTransaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
+ const bool frameNumberChanged = state.bufferData->flags.test(
+ BufferData::BufferDataChange::frameNumberChanged);
+ if (frameNumberChanged) {
+ flushState.bufferLayersReadyToPresent
+ .emplace_or_replace(state.surface.get(),
+ state.bufferData->frameNumber);
+ } else {
+ // Barrier function only used for BBQ which always includes a frame number.
+ // This value only used for barrier logic.
+ flushState.bufferLayersReadyToPresent
+ .emplace_or_replace(state.surface.get(),
+ std::numeric_limits<uint64_t>::max());
+ }
+ });
+ } else if (ready == TransactionReadiness::ReadyUnsignaledSingle) {
+ // Track queues with a flushed unsingaled buffer.
+ flushState.queuesWithUnsignaledBuffers.emplace_back(queueToken);
+ break;
+ }
+ }
+
+ if (queue.empty()) {
+ it = mPendingTransactionQueues.erase(it);
+ } else {
+ it = std::next(it, 1);
+ }
+ }
+ return transactionsPendingBarrier;
+}
+
+void TransactionHandler::addTransactionReadyFilter(TransactionFilter&& filter) {
+ mTransactionReadyFilters.emplace_back(std::move(filter));
+}
+
+bool TransactionHandler::hasPendingTransactions() {
+ return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty();
+}
+
+void TransactionHandler::onTransactionQueueStalled(const TransactionState& transaction,
+ sp<ITransactionCompletedListener>& listener) {
+ if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transaction.id) !=
+ mStalledTransactions.end()) {
+ return;
+ }
+
+ mStalledTransactions.push_back(transaction.id);
+ listener->onTransactionQueueStalled();
+}
+
+void TransactionHandler::removeFromStalledTransactions(uint64_t id) {
+ auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id);
+ if (it != mStalledTransactions.end()) {
+ mStalledTransactions.erase(it);
+ }
+}
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/TransactionHandler.h b/services/surfaceflinger/TransactionHandler.h
new file mode 100644
index 0000000..237b48d
--- /dev/null
+++ b/services/surfaceflinger/TransactionHandler.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <semaphore.h>
+#include <cstdint>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <vector>
+
+#include <LocklessQueue.h>
+#include <TransactionState.h>
+#include <android-base/thread_annotations.h>
+#include <ftl/small_map.h>
+#include <ftl/small_vector.h>
+
+namespace android {
+class TransactionHandler {
+public:
+ struct TransactionFlushState {
+ const TransactionState* transaction;
+ bool firstTransaction = true;
+ nsecs_t queueProcessTime = 0;
+ // Layer handles that have transactions with buffers that are ready to be applied.
+ ftl::SmallMap<IBinder* /* binder address */, uint64_t /* framenumber */, 15>
+ bufferLayersReadyToPresent = {};
+ ftl::SmallVector<IBinder* /* queueToken */, 15> queuesWithUnsignaledBuffers;
+ };
+ enum class TransactionReadiness {
+ NotReady,
+ NotReadyBarrier,
+ Ready,
+ ReadyUnsignaled,
+ ReadyUnsignaledSingle,
+ };
+ using TransactionFilter = std::function<TransactionReadiness(const TransactionFlushState&)>;
+
+ bool hasPendingTransactions();
+ std::vector<TransactionState> flushTransactions();
+ void addTransactionReadyFilter(TransactionFilter&&);
+ void queueTransaction(TransactionState&&);
+ void onTransactionQueueStalled(const TransactionState&, sp<ITransactionCompletedListener>&);
+ void removeFromStalledTransactions(uint64_t transactionId);
+
+private:
+ // For unit tests
+ friend class TestableSurfaceFlinger;
+
+ int flushPendingTransactionQueues(std::vector<TransactionState>&, TransactionFlushState&);
+ TransactionReadiness applyFilters(TransactionFlushState&);
+ std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
+ mPendingTransactionQueues;
+ LocklessQueue<TransactionState> mLocklessTransactionQueue;
+ std::atomic<size_t> mPendingTransactionCount = 0;
+ ftl::SmallVector<TransactionFilter, 2> mTransactionReadyFilters;
+ std::vector<uint64_t> mStalledTransactions;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 61f0fa6..3cbfe81 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -26,8 +26,6 @@
namespace android {
-class CountDownLatch;
-
struct TransactionState {
TransactionState() = default;
@@ -66,6 +64,15 @@
}
}
+ template <typename Visitor>
+ void traverseStatesWithBuffersWhileTrue(Visitor&& visitor) const {
+ for (const auto& [state] : states) {
+ if (state.hasBufferChanges() && state.hasValidBuffer() && state.surface) {
+ if (!visitor(state)) return;
+ }
+ }
+ }
+
// TODO(b/185535769): Remove FrameHint. Instead, reset the idle timer (of the relevant physical
// display) on the main thread if commit leads to composite. Then, RefreshRateOverlay should be
// able to setFrameRate once, rather than for each transaction.
@@ -97,49 +104,7 @@
int originPid;
int originUid;
uint64_t id;
- std::shared_ptr<CountDownLatch> transactionCommittedSignal;
bool sentFenceTimeoutWarning = false;
};
-class CountDownLatch {
-public:
- enum {
- eSyncTransaction = 1 << 0,
- };
- 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::nanoseconds& 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/Utils/Dumper.h b/services/surfaceflinger/Utils/Dumper.h
new file mode 100644
index 0000000..3761f9e
--- /dev/null
+++ b/services/surfaceflinger/Utils/Dumper.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+#include <string_view>
+
+namespace android::utils {
+
+// Dumps variables by appending their name and value to the output string. A variable is formatted
+// as "name=value". If the name or value is empty, the format is "value" or "name=", respectively.
+// A value of user-defined type T is stringified via `std::string to_string(const T&)`, which must
+// be defined in the same namespace as T per the rules of ADL (argument-dependent lookup).
+//
+// TODO(b/249828573): Consolidate with <compositionengine/impl/DumpHelpers.h>
+class Dumper {
+public:
+ explicit Dumper(std::string& out) : mOut(out) {}
+
+ void eol() { mOut += '\n'; }
+
+ void dump(std::string_view name, std::string_view value = {}) {
+ using namespace std::string_view_literals;
+
+ for (int i = mIndent; i-- > 0;) mOut += " "sv;
+ mOut += name;
+ if (!name.empty()) mOut += '=';
+ mOut += value;
+ eol();
+ }
+
+ void dump(std::string_view name, bool value) {
+ using namespace std::string_view_literals;
+ dump(name, value ? "true"sv : "false"sv);
+ }
+
+ template <typename T>
+ void dump(std::string_view name, const std::optional<T>& value) {
+ using namespace std::string_view_literals;
+ using std::to_string;
+ dump(name, value ? to_string(*value) : "nullopt"sv);
+ }
+
+ struct Indent {
+ explicit Indent(Dumper& dumper) : dumper(dumper) { dumper.mIndent++; }
+ ~Indent() { dumper.mIndent--; }
+
+ Dumper& dumper;
+ };
+
+private:
+ std::string& mOut;
+ int mIndent = 0;
+};
+
+} // namespace android::utils
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index fae9165..f8fc6f5 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -116,7 +116,7 @@
class DisplayHardwareFuzzer {
public:
DisplayHardwareFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
- mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value_or(
+ mPhysicalDisplayId = TestableSurfaceFlinger::getFirstDisplayId().value_or(
PhysicalDisplayId::fromPort(mFdp.ConsumeIntegral<uint8_t>()));
};
void process();
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index 79112bd..22d80ca 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -130,7 +130,7 @@
mFlinger->maxFrameBufferAcquiredBuffers = mFdp.ConsumeIntegral<int64_t>();
mFlinger->maxGraphicsWidth = mFdp.ConsumeIntegral<uint32_t>();
mFlinger->maxGraphicsHeight = mFdp.ConsumeIntegral<uint32_t>();
- mFlinger->hasWideColorDisplay = mFdp.ConsumeBool();
+ mTestableFlinger.mutableSupportsWideColor() = mFdp.ConsumeBool();
mFlinger->useContextPriority = mFdp.ConsumeBool();
mFlinger->defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 69dbfe0..ed2fe23 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -46,7 +46,6 @@
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerDefaultFactory.h"
-#include "SurfaceInterceptor.h"
#include "ThreadContext.h"
#include "TimeStats/TimeStats.h"
@@ -60,7 +59,6 @@
#include "tests/unittests/mock/MockFrameTimeline.h"
#include "tests/unittests/mock/MockFrameTracer.h"
#include "tests/unittests/mock/MockNativeWindowSurface.h"
-#include "tests/unittests/mock/MockSurfaceInterceptor.h"
#include "tests/unittests/mock/MockTimeStats.h"
#include "tests/unittests/mock/MockVSyncTracker.h"
#include "tests/unittests/mock/MockVsyncController.h"
@@ -316,10 +314,6 @@
return nullptr;
}
- sp<SurfaceInterceptor> createSurfaceInterceptor() override {
- return sp<android::impl::SurfaceInterceptor>::make();
- }
-
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
return sp<StartPropertySetThread>::make(timestampPropertyValue);
}
@@ -455,10 +449,6 @@
mFlinger->calculateColorMatrix(fdp->ConsumeFloatingPoint<float>());
mFlinger->updateColorMatrixLocked();
mFlinger->CheckTransactCodeCredentials(fdp->ConsumeIntegral<uint32_t>());
-
- const CountDownLatch transactionCommittedSignal(fdp->ConsumeIntegral<uint32_t>());
- mFlinger->waitForSynchronousTransaction(transactionCommittedSignal);
- mFlinger->signalSynchronousTransactions(fdp->ConsumeIntegral<uint32_t>());
}
void getCompositionPreference() {
@@ -526,6 +516,13 @@
mFlinger->setVsyncConfig(vsyncConfig, fdp->ConsumeIntegral<nsecs_t>());
}
+ // TODO(b/248317436): extend to cover all displays for multi-display devices
+ static std::optional<PhysicalDisplayId> getFirstDisplayId() {
+ std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ if (ids.empty()) return {};
+ return ids.front();
+ }
+
sp<IBinder> fuzzBoot(FuzzedDataProvider *fdp) {
mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool());
const sp<Client> client = sp<Client>::make(mFlinger);
@@ -537,9 +534,8 @@
ui::PixelFormat pixelFormat{};
mFlinger->getHwComposer().allocateVirtualDisplay(halVirtualDisplayId, uiSize, &pixelFormat);
- PhysicalDisplayId physicalDisplayId =
- SurfaceComposerClient::getInternalDisplayId().value_or(
- PhysicalDisplayId::fromPort(fdp->ConsumeIntegral<uint8_t>()));
+ PhysicalDisplayId physicalDisplayId = getFirstDisplayId().value_or(
+ PhysicalDisplayId::fromPort(fdp->ConsumeIntegral<uint8_t>()));
mFlinger->getHwComposer().allocatePhysicalDisplay(kHwDisplayId, physicalDisplayId);
sp<IBinder> display =
@@ -580,8 +576,6 @@
onPullAtom(&mFdp);
- mFlinger->injectVSync(mFdp.ConsumeIntegral<nsecs_t>());
-
getCompositionPreference();
getDisplayedContentSample(display, &mFdp);
getDesiredDisplayModeSpecs(display);
@@ -732,8 +726,10 @@
return mFlinger->setPowerModeInternal(display, mode);
}
- auto &getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; }
- auto &getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
+ auto &getTransactionQueue() { return mFlinger->mTransactionHandler.mLocklessTransactionQueue; }
+ auto &getPendingTransactionQueue() {
+ return mFlinger->mTransactionHandler.mPendingTransactionQueues;
+ }
auto setTransactionState(
const FrameTimelineInfo &frameTimelineInfo, const Vector<ComposerState> &states,
@@ -761,11 +757,10 @@
/* Read-write access to private data to set up preconditions and assert
* post-conditions.
*/
-
- auto &mutableCurrentState() { return mFlinger->mCurrentState; }
- auto &mutableDisplays() { return mFlinger->mDisplays; }
- auto &mutableDrawingState() { return mFlinger->mDrawingState; }
- auto &mutableInterceptor() { return mFlinger->mInterceptor; }
+ auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; }
+ auto& mutableCurrentState() { return mFlinger->mCurrentState; }
+ auto& mutableDisplays() { return mFlinger->mDisplays; }
+ auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto fromHandle(const sp<IBinder> &handle) { return mFlinger->fromHandle(handle); }
@@ -773,7 +768,6 @@
mutableDisplays().clear();
mutableCurrentState().displays.clear();
mutableDrawingState().displays.clear();
- mutableInterceptor().clear();
mFlinger->mScheduler.reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mCompositionEngine->setRenderEngine(
@@ -782,7 +776,7 @@
private:
void setVsyncEnabled(bool) override {}
- void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override {}
+ void requestDisplayModes(std::vector<scheduler::DisplayModeConfig>) override {}
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() override {}
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 66bac44..2614288 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -92,7 +92,7 @@
const auto getVsyncPeriod = [](uid_t /* uid */) { return kSyncPeriod.count(); };
std::unique_ptr<android::impl::EventThread> thread = std::make_unique<
android::impl::EventThread>(std::move(std::make_unique<FuzzImplVSyncSource>()), nullptr,
- nullptr, nullptr, getVsyncPeriod);
+ nullptr, getVsyncPeriod);
thread->onHotplugReceived(getPhysicalDisplayId(), mFdp.ConsumeBool());
sp<EventThreadConnection> connection =
@@ -362,11 +362,24 @@
mFdp.ConsumeFloatingPoint<float>()),
globalSignals);
- refreshRateConfigs.setDisplayManagerPolicy(
- {modeId,
- {Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
- Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
- FTL_FAKE_GUARD(kMainThreadContext, refreshRateConfigs.setActiveModeId(modeId));
+ {
+ ftl::FakeGuard guard(kMainThreadContext);
+
+ refreshRateConfigs.setPolicy(
+ RefreshRateConfigs::
+ DisplayManagerPolicy{modeId,
+ {Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+ Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
+ refreshRateConfigs.setPolicy(
+ RefreshRateConfigs::OverridePolicy{modeId,
+ {Fps::fromValue(
+ mFdp.ConsumeFloatingPoint<float>()),
+ Fps::fromValue(
+ mFdp.ConsumeFloatingPoint<float>())}});
+ refreshRateConfigs.setPolicy(RefreshRateConfigs::NoOverridePolicy{});
+
+ refreshRateConfigs.setActiveModeId(modeId);
+ }
RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue(
mFdp.ConsumeFloatingPoint<float>()),
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index b687abc..4c6a9cf 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -98,8 +98,7 @@
eReparent = 0x00008000;
eColorChanged = 0x00010000;
- eDestroySurface = 0x00020000;
- eTransformChanged = 0x00040000;
+ eBufferTransformChanged = 0x00040000;
eTransformToDisplayInverseChanged = 0x00080000;
eCropChanged = 0x00100000;
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 13ce65d..bd6367d 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -56,13 +56,11 @@
"SetFrameRateOverride_test.cpp",
"SetGeometry_test.cpp",
"Stress_test.cpp",
- "SurfaceInterceptor_test.cpp",
"VirtualDisplay_test.cpp",
"WindowInfosListener_test.cpp",
],
data: ["SurfaceFlinger_test.filter"],
static_libs: [
- "libtrace_proto",
"liblayers_proto",
"android.hardware.graphics.composer@2.1",
],
@@ -128,7 +126,6 @@
}
subdirs = [
- "fakehwc",
"hwc2",
"unittests",
"utils",
diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
index 432e227..f2874ae 100644
--- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp
+++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
@@ -30,7 +30,10 @@
TEST(BootDisplayModeTest, setBootDisplayMode) {
sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
- auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
bool bootModeSupport = false;
binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status));
@@ -42,7 +45,9 @@
TEST(BootDisplayModeTest, clearBootDisplayMode) {
sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
- auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
bool bootModeSupport = false;
binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status));
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 775de4a..4f04934 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -74,8 +74,17 @@
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
}
+ static sp<IBinder> getFirstDisplayToken() {
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ if (ids.empty()) {
+ return nullptr;
+ }
+
+ return SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
+ }
+
void setupBackgroundSurface() {
- mDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ mDisplay = getFirstDisplayToken();
ASSERT_FALSE(mDisplay == nullptr);
ui::DisplayMode mode;
@@ -158,9 +167,7 @@
}
TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
- std::function<bool()> condition = [] {
- return SurfaceComposerClient::getInternalDisplayToken() != nullptr;
- };
+ std::function<bool()> condition = [] { return getFirstDisplayToken() != nullptr; };
// Anyone can access display information.
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
}
@@ -169,7 +176,7 @@
// The following methods are tested with a UID that is not root, graphics,
// or system, to show that anyone can access them.
UIDFaker f(AID_BIN);
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
ASSERT_TRUE(display != nullptr);
ui::DisplayMode mode;
@@ -181,7 +188,7 @@
}
TEST_F(CredentialsTest, GetDynamicDisplayInfoTest) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
std::function<status_t()> condition = [=]() {
ui::DynamicDisplayInfo info;
return SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
@@ -190,7 +197,7 @@
}
TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
std::function<status_t()> condition = [=]() {
ui::DisplayPrimaries primaries;
return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries);
@@ -199,7 +206,7 @@
}
TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
ui::DisplayModeId defaultMode;
bool allowGroupSwitching;
float primaryFpsMin;
@@ -222,7 +229,7 @@
}
TEST_F(CredentialsTest, SetActiveColorModeTest) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
std::function<status_t()> condition = [=]() {
return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE);
};
@@ -274,7 +281,7 @@
}
TEST_F(CredentialsTest, CaptureTest) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
std::function<status_t()> condition = [=]() {
sp<GraphicBuffer> outBuffer;
DisplayCaptureArgs captureArgs;
@@ -333,7 +340,7 @@
}
TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
ASSERT_FALSE(display == nullptr);
bool result = false;
status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result);
@@ -357,7 +364,7 @@
}
TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
ASSERT_FALSE(display == nullptr);
std::function<status_t()> condition = [=]() {
bool result = false;
@@ -367,7 +374,7 @@
}
TEST_F(CredentialsTest, GetActiveColorModeBasicCorrectness) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = getFirstDisplayToken();
ASSERT_FALSE(display == nullptr);
ui::DynamicDisplayInfo info;
SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 2dc96b8..02c934e 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -48,7 +48,9 @@
protected:
void SetUp() override {
- mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
status_t res =
SurfaceComposerClient::getDesiredDisplayModeSpecs(mDisplayToken,
&initialDefaultMode,
@@ -149,4 +151,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/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
index 9fa0452..52aa502 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -28,7 +28,9 @@
LayerTransactionTest::SetUp();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_FALSE(display == nullptr);
mParentLayer = createColorLayer("Parent layer", Color::RED);
@@ -177,7 +179,9 @@
}
TEST_F(EffectLayerTest, EffectLayerWithColorNoCrop) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ui::DisplayMode mode;
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
const ui::Size& resolution = mode.resolution;
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index c63d251..40a5d57 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -224,7 +224,9 @@
mClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
- mPrimaryDisplay = mClient->getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ mPrimaryDisplay = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ui::DisplayMode mode;
mClient->getActiveDisplayMode(mPrimaryDisplay, &mode);
mDisplayWidth = mode.resolution.getWidth();
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 741b6f7..666ce76 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -48,7 +48,7 @@
}
sp<SurfaceControl> makeNotSurfaceControl() {
- return sp<SurfaceControl>::make(mScc, sp<NotALayer>::make(), 1);
+ return sp<SurfaceControl>::make(mScc, sp<NotALayer>::make(), 1, "#1");
}
};
diff --git a/services/surfaceflinger/tests/LayerBorder_test.cpp b/services/surfaceflinger/tests/LayerBorder_test.cpp
index 85108ad..00e134b 100644
--- a/services/surfaceflinger/tests/LayerBorder_test.cpp
+++ b/services/surfaceflinger/tests/LayerBorder_test.cpp
@@ -34,7 +34,9 @@
toHalf3 = ColorTransformHelper::toHalf3;
toHalf4 = ColorTransformHelper::toHalf4;
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_FALSE(display == nullptr);
mColorOrange = toHalf4({255, 140, 0, 255});
mParentLayer = createColorLayer("Parent layer", Color::RED);
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 774c1d7..badd5be 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -289,7 +289,9 @@
private:
void SetUpDisplay() {
- mDisplay = mClient->getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ mDisplay = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
ui::DisplayMode mode;
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index e1a7ecc..867eddb 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -33,7 +33,9 @@
LayerTransactionTest::SetUp();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_FALSE(display == nullptr);
ui::DisplayMode mode;
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index faaef5d..e69db7c 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -29,8 +29,10 @@
virtual void SetUp() {
LayerTransactionTest::SetUp();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_FALSE(display == nullptr);
mParentLayer = createColorLayer("Parent layer", Color::RED);
@@ -231,7 +233,10 @@
// Test that the mirror layer is initially offscreen.
TEST_F(MirrorLayerTest, InitialMirrorState) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ui::DisplayMode mode;
SurfaceComposerClient::getActiveDisplayMode(display, &mode);
const ui::Size& size = mode.resolution;
@@ -275,7 +280,9 @@
// Test that a mirror layer can be screenshot when offscreen
TEST_F(MirrorLayerTest, OffscreenMirrorScreenshot) {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ui::DisplayMode mode;
SurfaceComposerClient::getActiveDisplayMode(display, &mode);
const ui::Size& size = mode.resolution;
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index 1ed6c65..15ff696 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -35,7 +35,9 @@
LayerTransactionTest::SetUp();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
- mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ mMainDisplay = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState);
SurfaceComposerClient::getActiveDisplayMode(mMainDisplay, &mMainDisplayMode);
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
index 50a4092..9cebf11 100644
--- a/services/surfaceflinger/tests/RelativeZ_test.cpp
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -33,7 +33,9 @@
LayerTransactionTest::SetUp();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_FALSE(display == nullptr);
// Back layer
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 3a5e532..976ee35 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -30,7 +30,9 @@
LayerTransactionTest::SetUp();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ ASSERT_FALSE(ids.empty());
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ASSERT_FALSE(display == nullptr);
ui::DisplayMode mode;
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
deleted file mode 100644
index d79e592..0000000
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * Copyright (C) 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"
-#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>
-#include <gui/ISurfaceComposer.h>
-#include <gui/LayerState.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-#include <private/gui/ComposerService.h>
-#include <ui/DisplayMode.h>
-
-#include <fstream>
-#include <random>
-#include <thread>
-
-namespace android {
-
-using Transaction = SurfaceComposerClient::Transaction;
-using SurfaceChange = surfaceflinger::SurfaceChange;
-using Trace = surfaceflinger::Trace;
-using Increment = surfaceflinger::Increment;
-
-constexpr uint32_t BUFFER_UPDATES = 18;
-constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
-constexpr uint32_t SIZE_UPDATE = 134;
-constexpr uint32_t STACK_UPDATE = 1;
-constexpr int32_t RELATIVE_Z = 42;
-constexpr float ALPHA_UPDATE = 0.29f;
-constexpr float CORNER_RADIUS_UPDATE = 0.2f;
-constexpr int BACKGROUND_BLUR_RADIUS_UPDATE = 24;
-constexpr float POSITION_UPDATE = 121;
-const Rect CROP_UPDATE(16, 16, 32, 32);
-const float SHADOW_RADIUS_UPDATE = 35.0f;
-std::vector<BlurRegion> BLUR_REGIONS_UPDATE;
-
-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 LAYER_NAME = "Layer Create and Delete Test";
-
-constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope";
-
-// Fill an RGBA_8888 formatted surface with a single color.
-static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
- ANativeWindow_Buffer outBuffer;
- sp<Surface> s = sc->getSurface();
- ASSERT_TRUE(s != nullptr);
- ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
- uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
- for (int y = 0; y < outBuffer.height; y++) {
- for (int x = 0; x < outBuffer.width; x++) {
- uint8_t* pixel = img + (4 * (y*outBuffer.stride + x));
- pixel[0] = r;
- pixel[1] = g;
- pixel[2] = b;
- pixel[3] = 255;
- }
- }
- ASSERT_EQ(NO_ERROR, s->unlockAndPost());
-}
-
-static status_t readProtoFile(Trace* trace) {
- status_t err = NO_ERROR;
-
- int fd = open(DEFAULT_FILENAME, O_RDONLY);
- {
- google::protobuf::io::FileInputStream f(fd);
- if (fd && !trace->ParseFromZeroCopyStream(&f)) {
- err = PERMISSION_DENIED;
- }
- }
- close(fd);
-
- return err;
-}
-
-static void enableInterceptor() {
- system("service call SurfaceFlinger 1020 i32 1 > /dev/null");
-}
-
-static void disableInterceptor() {
- 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() == getUniqueName(surfaceName, increment)) {
- layerId = increment.surface_creation().id();
- }
- }
- }
- return layerId;
-}
-
-int32_t getDisplayId(const Trace& capturedTrace, const std::string& displayName) {
- int32_t displayId = 0;
- for (const auto& increment : capturedTrace.increment()) {
- if (increment.increment_case() == increment.kDisplayCreation) {
- if (increment.display_creation().name() == displayName) {
- displayId = increment.display_creation().id();
- break;
- }
- }
- }
- return displayId;
-}
-
-class SurfaceInterceptorTest : public ::testing::Test {
-protected:
- void SetUp() override {
- // Allow SurfaceInterceptor write to /data
- system("setenforce 0");
-
- mComposerClient = sp<SurfaceComposerClient>::make();
- ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
- GTEST_SKIP();
- }
-
- void TearDown() override {
- mComposerClient->dispose();
- mBGSurfaceControl.clear();
- mFGSurfaceControl.clear();
- mComposerClient.clear();
- system("setenforce 1");
- }
-
- sp<SurfaceComposerClient> mComposerClient;
- sp<SurfaceControl> mBGSurfaceControl;
- sp<SurfaceControl> mFGSurfaceControl;
- int32_t mBGLayerId;
- int32_t mFGLayerId;
-
-public:
- using TestTransactionAction = void (SurfaceInterceptorTest::*)(Transaction&);
- using TestAction = void (SurfaceInterceptorTest::*)();
- using TestBooleanVerification = bool (SurfaceInterceptorTest::*)(const Trace&);
- using TestVerification = void (SurfaceInterceptorTest::*)(const Trace&);
-
- void setupBackgroundSurface();
- void preProcessTrace(const Trace& trace);
-
- // captureTest will enable SurfaceInterceptor, setup background surface,
- // disable SurfaceInterceptor, collect the trace and process the trace for
- // id of background surface before further verification.
- void captureTest(TestTransactionAction action, TestBooleanVerification verification);
- void captureTest(TestTransactionAction action, SurfaceChange::SurfaceChangeCase changeCase);
- void captureTest(TestTransactionAction action, Increment::IncrementCase incrementCase);
- void captureTest(TestAction action, TestBooleanVerification verification);
- void captureTest(TestAction action, TestVerification verification);
- void runInTransaction(TestTransactionAction action);
-
- // Verification of changes to a surface
- bool positionUpdateFound(const SurfaceChange& change, bool foundPosition);
- bool sizeUpdateFound(const SurfaceChange& change, bool foundSize);
- bool alphaUpdateFound(const SurfaceChange& change, bool foundAlpha);
- bool layerUpdateFound(const SurfaceChange& change, bool foundLayer);
- bool cropUpdateFound(const SurfaceChange& change, bool foundCrop);
- bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
- bool backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
- bool foundBackgroundBlurRadius);
- bool blurRegionsUpdateFound(const SurfaceChange& change, bool foundBlurRegions);
- bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
- bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
- bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
- bool layerStackUpdateFound(const SurfaceChange& change, bool foundLayerStack);
- bool hiddenFlagUpdateFound(const SurfaceChange& change, bool foundHiddenFlag);
- bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag);
- bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag);
- bool reparentUpdateFound(const SurfaceChange& change, bool found);
- bool relativeParentUpdateFound(const SurfaceChange& change, bool found);
- bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found);
- bool trustedOverlayUpdateFound(const SurfaceChange& change, bool found);
- bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
-
- // Find all of the updates in the single trace
- void assertAllUpdatesFound(const Trace& trace);
-
- // Verification of creation and deletion of a surface
- bool surfaceCreationFound(const Increment& increment, bool foundSurface);
- bool surfaceDeletionFound(const Increment& increment, const int32_t targetId,
- bool foundSurface);
- bool displayCreationFound(const Increment& increment, bool foundDisplay);
- bool displayDeletionFound(const Increment& increment, const int32_t targetId,
- bool foundDisplay);
- bool singleIncrementFound(const Trace& trace, Increment::IncrementCase incrementCase);
-
- // Verification of buffer updates
- bool bufferUpdatesFound(const Trace& trace);
-
- // Perform each of the possible changes to a surface
- void positionUpdate(Transaction&);
- void sizeUpdate(Transaction&);
- void alphaUpdate(Transaction&);
- void layerUpdate(Transaction&);
- void cropUpdate(Transaction&);
- void cornerRadiusUpdate(Transaction&);
- void backgroundBlurRadiusUpdate(Transaction&);
- void blurRegionsUpdate(Transaction&);
- void matrixUpdate(Transaction&);
- void transparentRegionHintUpdate(Transaction&);
- void layerStackUpdate(Transaction&);
- void hiddenFlagUpdate(Transaction&);
- void opaqueFlagUpdate(Transaction&);
- void secureFlagUpdate(Transaction&);
- void reparentUpdate(Transaction&);
- void relativeParentUpdate(Transaction&);
- void shadowRadiusUpdate(Transaction&);
- void trustedOverlayUpdate(Transaction&);
- void surfaceCreation(Transaction&);
- void displayCreation(Transaction&);
- void displayDeletion(Transaction&);
-
- void nBufferUpdates();
- void runAllUpdates();
-
-private:
- void captureInTransaction(TestTransactionAction action, Trace*);
- void capture(TestAction action, Trace*);
-};
-
-void SurfaceInterceptorTest::captureInTransaction(TestTransactionAction action, Trace* outTrace) {
- enableInterceptor();
- setupBackgroundSurface();
- runInTransaction(action);
- disableInterceptor();
- ASSERT_EQ(NO_ERROR, readProtoFile(outTrace));
- preProcessTrace(*outTrace);
-}
-
-void SurfaceInterceptorTest::capture(TestAction action, Trace* outTrace) {
- enableInterceptor();
- setupBackgroundSurface();
- (this->*action)();
- disableInterceptor();
- ASSERT_EQ(NO_ERROR, readProtoFile(outTrace));
- preProcessTrace(*outTrace);
-}
-
-void SurfaceInterceptorTest::setupBackgroundSurface() {
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
- ASSERT_FALSE(display == nullptr);
-
- ui::DisplayMode mode;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- const ui::Size& resolution = mode.resolution;
-
- // Background surface
- mBGSurfaceControl =
- mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), resolution.getWidth(),
- resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mBGSurfaceControl != nullptr);
- ASSERT_TRUE(mBGSurfaceControl->isValid());
-
- // Foreground surface
- mFGSurfaceControl =
- mComposerClient->createSurface(String8(TEST_FG_SURFACE_NAME), resolution.getWidth(),
- resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mFGSurfaceControl != nullptr);
- ASSERT_TRUE(mFGSurfaceControl->isValid());
-
- Transaction t;
- t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
- ASSERT_EQ(NO_ERROR,
- t.setLayer(mBGSurfaceControl, INT_MAX - 3)
- .show(mBGSurfaceControl)
- .setLayer(mFGSurfaceControl, INT_MAX - 3)
- .show(mFGSurfaceControl)
- .apply());
-}
-
-void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) {
- mBGLayerId = getSurfaceId(trace, TEST_BG_SURFACE_NAME);
- mFGLayerId = getSurfaceId(trace, TEST_FG_SURFACE_NAME);
-}
-
-void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
- TestBooleanVerification verification) {
- Trace capturedTrace;
- captureInTransaction(action, &capturedTrace);
- ASSERT_TRUE((this->*verification)(capturedTrace));
-}
-
-void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
- Increment::IncrementCase incrementCase) {
- Trace capturedTrace;
- captureInTransaction(action, &capturedTrace);
- ASSERT_TRUE(singleIncrementFound(capturedTrace, incrementCase));
-}
-
-void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
- SurfaceChange::SurfaceChangeCase changeCase) {
- Trace capturedTrace;
- captureInTransaction(action, &capturedTrace);
- ASSERT_TRUE(surfaceUpdateFound(capturedTrace, changeCase));
-}
-
-void SurfaceInterceptorTest::captureTest(TestAction action, TestBooleanVerification verification) {
- Trace capturedTrace;
- capture(action, &capturedTrace);
- ASSERT_TRUE((this->*verification)(capturedTrace));
-}
-
-void SurfaceInterceptorTest::captureTest(TestAction action, TestVerification verification) {
- Trace capturedTrace;
- capture(action, &capturedTrace);
- (this->*verification)(capturedTrace);
-}
-
-void SurfaceInterceptorTest::runInTransaction(TestTransactionAction action) {
- Transaction t;
- (this->*action)(t);
- t.apply(true);
-}
-
-void SurfaceInterceptorTest::positionUpdate(Transaction& t) {
- t.setPosition(mBGSurfaceControl, POSITION_UPDATE, POSITION_UPDATE);
-}
-
-void SurfaceInterceptorTest::sizeUpdate(Transaction&) {}
-
-void SurfaceInterceptorTest::alphaUpdate(Transaction& t) {
- t.setAlpha(mBGSurfaceControl, ALPHA_UPDATE);
-}
-
-void SurfaceInterceptorTest::cornerRadiusUpdate(Transaction& t) {
- t.setCornerRadius(mBGSurfaceControl, CORNER_RADIUS_UPDATE);
-}
-
-void SurfaceInterceptorTest::backgroundBlurRadiusUpdate(Transaction& t) {
- t.setBackgroundBlurRadius(mBGSurfaceControl, BACKGROUND_BLUR_RADIUS_UPDATE);
-}
-
-void SurfaceInterceptorTest::blurRegionsUpdate(Transaction& t) {
- BLUR_REGIONS_UPDATE.empty();
- BLUR_REGIONS_UPDATE.push_back(BlurRegion());
- t.setBlurRegions(mBGSurfaceControl, BLUR_REGIONS_UPDATE);
-}
-
-void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
- t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
-}
-
-void SurfaceInterceptorTest::cropUpdate(Transaction& t) {
- t.setCrop(mBGSurfaceControl, CROP_UPDATE);
-}
-
-void SurfaceInterceptorTest::matrixUpdate(Transaction& t) {
- t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
-}
-
-void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) {
- Region region(CROP_UPDATE);
- t.setTransparentRegionHint(mBGSurfaceControl, region);
-}
-
-void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) {
- t.setLayerStack(mBGSurfaceControl, ui::LayerStack::fromValue(STACK_UPDATE));
-}
-
-void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) {
- t.setFlags(mBGSurfaceControl, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
-}
-
-void SurfaceInterceptorTest::opaqueFlagUpdate(Transaction& t) {
- t.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
-}
-
-void SurfaceInterceptorTest::secureFlagUpdate(Transaction& t) {
- t.setFlags(mBGSurfaceControl, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
-}
-
-void SurfaceInterceptorTest::reparentUpdate(Transaction& t) {
- t.reparent(mBGSurfaceControl, mFGSurfaceControl);
-}
-
-void SurfaceInterceptorTest::relativeParentUpdate(Transaction& t) {
- t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl, RELATIVE_Z);
-}
-
-void SurfaceInterceptorTest::shadowRadiusUpdate(Transaction& t) {
- t.setShadowRadius(mBGSurfaceControl, SHADOW_RADIUS_UPDATE);
-}
-
-void SurfaceInterceptorTest::trustedOverlayUpdate(Transaction& t) {
- t.setTrustedOverlay(mBGSurfaceControl, true);
-}
-
-void SurfaceInterceptorTest::displayCreation(Transaction&) {
- sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
- SurfaceComposerClient::destroyDisplay(testDisplay);
-}
-
-void SurfaceInterceptorTest::displayDeletion(Transaction&) {
- sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
- SurfaceComposerClient::destroyDisplay(testDisplay);
-}
-
-void SurfaceInterceptorTest::runAllUpdates() {
- runInTransaction(&SurfaceInterceptorTest::positionUpdate);
- runInTransaction(&SurfaceInterceptorTest::sizeUpdate);
- runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
- runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
- runInTransaction(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate);
- runInTransaction(&SurfaceInterceptorTest::blurRegionsUpdate);
- runInTransaction(&SurfaceInterceptorTest::layerUpdate);
- runInTransaction(&SurfaceInterceptorTest::cropUpdate);
- runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
- runInTransaction(&SurfaceInterceptorTest::transparentRegionHintUpdate);
- runInTransaction(&SurfaceInterceptorTest::layerStackUpdate);
- runInTransaction(&SurfaceInterceptorTest::hiddenFlagUpdate);
- runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate);
- runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate);
- runInTransaction(&SurfaceInterceptorTest::reparentUpdate);
- runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate);
- runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate);
- runInTransaction(&SurfaceInterceptorTest::trustedOverlayUpdate);
-}
-
-void SurfaceInterceptorTest::surfaceCreation(Transaction&) {
- mComposerClient->createSurface(String8(LAYER_NAME), SIZE_UPDATE, SIZE_UPDATE,
- PIXEL_FORMAT_RGBA_8888, 0);
-}
-
-void SurfaceInterceptorTest::nBufferUpdates() {
- std::random_device rd;
- std::mt19937_64 gen(rd());
- // This makes testing fun
- std::uniform_int_distribution<uint8_t> dis;
- for (uint32_t i = 0; i < BUFFER_UPDATES; ++i) {
- fillSurfaceRGBA8(mBGSurfaceControl, dis(gen), dis(gen), dis(gen));
- }
-}
-
-bool SurfaceInterceptorTest::positionUpdateFound(const SurfaceChange& change, bool foundPosition) {
- // There should only be one position transaction with x and y = POSITION_UPDATE
- bool hasX(change.position().x() == POSITION_UPDATE);
- bool hasY(change.position().y() == POSITION_UPDATE);
- if (hasX && hasY && !foundPosition) {
- foundPosition = true;
- } else if (hasX && hasY && foundPosition) {
- // Failed because the position update was found a second time
- [] () { FAIL(); }();
- }
- return foundPosition;
-}
-
-bool SurfaceInterceptorTest::sizeUpdateFound(const SurfaceChange&, bool) {
- return true;
-}
-
-bool SurfaceInterceptorTest::alphaUpdateFound(const SurfaceChange& change, bool foundAlpha) {
- bool hasAlpha(change.alpha().alpha() == ALPHA_UPDATE);
- if (hasAlpha && !foundAlpha) {
- foundAlpha = true;
- } else if (hasAlpha && foundAlpha) {
- [] () { FAIL(); }();
- }
- return foundAlpha;
-}
-
-bool SurfaceInterceptorTest::cornerRadiusUpdateFound(const SurfaceChange &change,
- bool foundCornerRadius) {
- bool hasCornerRadius(change.corner_radius().corner_radius() == CORNER_RADIUS_UPDATE);
- if (hasCornerRadius && !foundCornerRadius) {
- foundCornerRadius = true;
- } else if (hasCornerRadius && foundCornerRadius) {
- [] () { FAIL(); }();
- }
- return foundCornerRadius;
-}
-
-bool SurfaceInterceptorTest::backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
- bool foundBackgroundBlur) {
- bool hasBackgroundBlur(change.background_blur_radius().background_blur_radius() ==
- BACKGROUND_BLUR_RADIUS_UPDATE);
- if (hasBackgroundBlur && !foundBackgroundBlur) {
- foundBackgroundBlur = true;
- } else if (hasBackgroundBlur && foundBackgroundBlur) {
- []() { FAIL(); }();
- }
- return foundBackgroundBlur;
-}
-
-bool SurfaceInterceptorTest::blurRegionsUpdateFound(const SurfaceChange& change,
- bool foundBlurRegions) {
- bool hasBlurRegions(change.blur_regions().blur_regions_size() == BLUR_REGIONS_UPDATE.size());
- if (hasBlurRegions && !foundBlurRegions) {
- foundBlurRegions = true;
- } else if (hasBlurRegions && foundBlurRegions) {
- []() { FAIL(); }();
- }
- return foundBlurRegions;
-}
-
-bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
- bool hasLayer(change.layer().layer() == LAYER_UPDATE);
- if (hasLayer && !foundLayer) {
- foundLayer = true;
- } else if (hasLayer && foundLayer) {
- [] () { FAIL(); }();
- }
- return foundLayer;
-}
-
-bool SurfaceInterceptorTest::cropUpdateFound(const SurfaceChange& change, bool foundCrop) {
- bool hasLeft(change.crop().rectangle().left() == CROP_UPDATE.left);
- bool hasTop(change.crop().rectangle().top() == CROP_UPDATE.top);
- bool hasRight(change.crop().rectangle().right() == CROP_UPDATE.right);
- bool hasBottom(change.crop().rectangle().bottom() == CROP_UPDATE.bottom);
- if (hasLeft && hasRight && hasTop && hasBottom && !foundCrop) {
- foundCrop = true;
- } else if (hasLeft && hasRight && hasTop && hasBottom && foundCrop) {
- [] () { FAIL(); }();
- }
- return foundCrop;
-}
-
-bool SurfaceInterceptorTest::matrixUpdateFound(const SurfaceChange& change, bool foundMatrix) {
- bool hasSx((float)change.matrix().dsdx() == (float)M_SQRT1_2);
- bool hasTx((float)change.matrix().dtdx() == (float)M_SQRT1_2);
- bool hasSy((float)change.matrix().dsdy() == (float)M_SQRT1_2);
- bool hasTy((float)change.matrix().dtdy() == (float)-M_SQRT1_2);
- if (hasSx && hasTx && hasSy && hasTy && !foundMatrix) {
- foundMatrix = true;
- } else if (hasSx && hasTx && hasSy && hasTy && foundMatrix) {
- [] () { FAIL(); }();
- }
- return foundMatrix;
-}
-
-bool SurfaceInterceptorTest::transparentRegionHintUpdateFound(const SurfaceChange& change,
- bool foundTransparentRegion) {
- auto traceRegion = change.transparent_region_hint().region(0);
- bool hasLeft(traceRegion.left() == CROP_UPDATE.left);
- bool hasTop(traceRegion.top() == CROP_UPDATE.top);
- bool hasRight(traceRegion.right() == CROP_UPDATE.right);
- bool hasBottom(traceRegion.bottom() == CROP_UPDATE.bottom);
- if (hasLeft && hasRight && hasTop && hasBottom && !foundTransparentRegion) {
- foundTransparentRegion = true;
- } else if (hasLeft && hasRight && hasTop && hasBottom && foundTransparentRegion) {
- [] () { FAIL(); }();
- }
- return foundTransparentRegion;
-}
-
-bool SurfaceInterceptorTest::layerStackUpdateFound(const SurfaceChange& change,
- bool foundLayerStack) {
- bool hasLayerStackUpdate(change.layer_stack().layer_stack() == STACK_UPDATE);
- if (hasLayerStackUpdate && !foundLayerStack) {
- foundLayerStack = true;
- } else if (hasLayerStackUpdate && foundLayerStack) {
- [] () { FAIL(); }();
- }
- return foundLayerStack;
-}
-
-bool SurfaceInterceptorTest::hiddenFlagUpdateFound(const SurfaceChange& change,
- bool foundHiddenFlag) {
- bool hasHiddenFlag(change.hidden_flag().hidden_flag());
- if (hasHiddenFlag && !foundHiddenFlag) {
- foundHiddenFlag = true;
- } else if (hasHiddenFlag && foundHiddenFlag) {
- [] () { FAIL(); }();
- }
- return foundHiddenFlag;
-}
-
-bool SurfaceInterceptorTest::opaqueFlagUpdateFound(const SurfaceChange& change,
- bool foundOpaqueFlag) {
- bool hasOpaqueFlag(change.opaque_flag().opaque_flag());
- if (hasOpaqueFlag && !foundOpaqueFlag) {
- foundOpaqueFlag = true;
- } else if (hasOpaqueFlag && foundOpaqueFlag) {
- [] () { FAIL(); }();
- }
- return foundOpaqueFlag;
-}
-
-bool SurfaceInterceptorTest::secureFlagUpdateFound(const SurfaceChange& change,
- bool foundSecureFlag) {
- bool hasSecureFlag(change.secure_flag().secure_flag());
- if (hasSecureFlag && !foundSecureFlag) {
- foundSecureFlag = true;
- } else if (hasSecureFlag && foundSecureFlag) {
- [] () { FAIL(); }();
- }
- return foundSecureFlag;
-}
-
-bool SurfaceInterceptorTest::reparentUpdateFound(const SurfaceChange& change, bool found) {
- bool hasId(change.reparent().parent_id() == mFGLayerId);
- if (hasId && !found) {
- found = true;
- } else if (hasId && found) {
- []() { FAIL(); }();
- }
- return found;
-}
-
-bool SurfaceInterceptorTest::relativeParentUpdateFound(const SurfaceChange& change, bool found) {
- bool hasId(change.relative_parent().relative_parent_id() == mFGLayerId);
- if (hasId && !found) {
- found = true;
- } else if (hasId && found) {
- []() { FAIL(); }();
- }
- return found;
-}
-
-bool SurfaceInterceptorTest::shadowRadiusUpdateFound(const SurfaceChange& change,
- bool foundShadowRadius) {
- bool hasShadowRadius(change.shadow_radius().radius() == SHADOW_RADIUS_UPDATE);
- if (hasShadowRadius && !foundShadowRadius) {
- foundShadowRadius = true;
- } else if (hasShadowRadius && foundShadowRadius) {
- []() { FAIL(); }();
- }
- return foundShadowRadius;
-}
-
-bool SurfaceInterceptorTest::trustedOverlayUpdateFound(const SurfaceChange& change,
- bool foundTrustedOverlay) {
- bool hasTrustedOverlay(change.trusted_overlay().is_trusted_overlay());
- if (hasTrustedOverlay && !foundTrustedOverlay) {
- foundTrustedOverlay = true;
- } else if (hasTrustedOverlay && foundTrustedOverlay) {
- []() { FAIL(); }();
- }
- return foundTrustedOverlay;
-}
-
-bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
- SurfaceChange::SurfaceChangeCase changeCase) {
- bool foundUpdate = false;
- for (const auto& increment : trace.increment()) {
- if (increment.increment_case() == increment.kTransaction) {
- for (const auto& change : increment.transaction().surface_change()) {
- if (change.id() == mBGLayerId && change.SurfaceChange_case() == changeCase) {
- switch (changeCase) {
- case SurfaceChange::SurfaceChangeCase::kPosition:
- // foundUpdate is sent for the tests to fail on duplicated increments
- foundUpdate = positionUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kSize:
- foundUpdate = sizeUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kAlpha:
- foundUpdate = alphaUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kLayer:
- foundUpdate = layerUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kCrop:
- foundUpdate = cropUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kCornerRadius:
- foundUpdate = cornerRadiusUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius:
- foundUpdate = backgroundBlurRadiusUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kBlurRegions:
- foundUpdate = blurRegionsUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kMatrix:
- foundUpdate = matrixUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
- foundUpdate = transparentRegionHintUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kLayerStack:
- foundUpdate = layerStackUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kHiddenFlag:
- foundUpdate = hiddenFlagUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kOpaqueFlag:
- foundUpdate = opaqueFlagUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kSecureFlag:
- foundUpdate = secureFlagUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kReparent:
- foundUpdate = reparentUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kRelativeParent:
- foundUpdate = relativeParentUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kShadowRadius:
- foundUpdate = shadowRadiusUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::kTrustedOverlay:
- foundUpdate = trustedOverlayUpdateFound(change, foundUpdate);
- break;
- case SurfaceChange::SurfaceChangeCase::SURFACECHANGE_NOT_SET:
- break;
- }
- }
- }
- }
- }
- return foundUpdate;
-}
-
-void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) {
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kPosition));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSize));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kAlpha));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayer));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kCrop));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kMatrix));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kTransparentRegionHint));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayerStack));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kHiddenFlag));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOpaqueFlag));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent));
- ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent));
-}
-
-bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
- bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment));
- if (isMatch && !foundSurface) {
- foundSurface = true;
- } else if (isMatch && foundSurface) {
- [] () { FAIL(); }();
- }
- return foundSurface;
-}
-
-bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment,
- const int32_t targetId, bool foundSurface) {
- bool isMatch(increment.surface_deletion().id() == targetId);
- if (isMatch && !foundSurface) {
- foundSurface = true;
- } else if (isMatch && foundSurface) {
- [] () { FAIL(); }();
- }
- return foundSurface;
-}
-
-bool SurfaceInterceptorTest::displayCreationFound(const Increment& increment, bool foundDisplay) {
- bool isMatch(increment.display_creation().name() == DISPLAY_NAME.string() &&
- !increment.display_creation().is_secure());
- if (isMatch && !foundDisplay) {
- foundDisplay = true;
- } else if (isMatch && foundDisplay) {
- [] () { FAIL(); }();
- }
- return foundDisplay;
-}
-
-bool SurfaceInterceptorTest::displayDeletionFound(const Increment& increment,
- const int32_t targetId, bool foundDisplay) {
- bool isMatch(increment.display_deletion().id() == targetId);
- if (isMatch && !foundDisplay) {
- foundDisplay = true;
- } else if (isMatch && foundDisplay) {
- [] () { FAIL(); }();
- }
- return foundDisplay;
-}
-
-bool SurfaceInterceptorTest::singleIncrementFound(const Trace& trace,
- Increment::IncrementCase incrementCase) {
- bool foundIncrement = false;
- for (const auto& increment : trace.increment()) {
- if (increment.increment_case() == incrementCase) {
- int32_t targetId = 0;
- switch (incrementCase) {
- case Increment::IncrementCase::kSurfaceCreation:
- foundIncrement = surfaceCreationFound(increment, foundIncrement);
- break;
- case Increment::IncrementCase::kSurfaceDeletion:
- // Find the id of created surface.
- targetId = getSurfaceId(trace, LAYER_NAME);
- foundIncrement = surfaceDeletionFound(increment, targetId, foundIncrement);
- break;
- case Increment::IncrementCase::kDisplayCreation:
- foundIncrement = displayCreationFound(increment, foundIncrement);
- break;
- case Increment::IncrementCase::kDisplayDeletion:
- // Find the id of created display.
- targetId = getDisplayId(trace, DISPLAY_NAME.string());
- foundIncrement = displayDeletionFound(increment, targetId, foundIncrement);
- break;
- default:
- /* code */
- break;
- }
- }
- }
- return foundIncrement;
-}
-
-bool SurfaceInterceptorTest::bufferUpdatesFound(const Trace& trace) {
- uint32_t updates = 0;
- for (const auto& inc : trace.increment()) {
- if (inc.increment_case() == inc.kBufferUpdate && inc.buffer_update().id() == mBGLayerId) {
- updates++;
- }
- }
- return updates == BUFFER_UPDATES;
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptPositionUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::positionUpdate,
- SurfaceChange::SurfaceChangeCase::kPosition);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptSizeUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::sizeUpdate, SurfaceChange::SurfaceChangeCase::kSize);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptAlphaUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::alphaUpdate, SurfaceChange::SurfaceChangeCase::kAlpha);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptLayerUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::layerUpdate, SurfaceChange::SurfaceChangeCase::kLayer);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptCropUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::cropUpdate, SurfaceChange::SurfaceChangeCase::kCrop);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptCornerRadiusUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::cornerRadiusUpdate,
- SurfaceChange::SurfaceChangeCase::kCornerRadius);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptBackgroundBlurRadiusUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate,
- SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptBlurRegionsUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::blurRegionsUpdate,
- SurfaceChange::SurfaceChangeCase::kBlurRegions);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptTransparentRegionHintUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::transparentRegionHintUpdate,
- SurfaceChange::SurfaceChangeCase::kTransparentRegionHint);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptLayerStackUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::layerStackUpdate,
- SurfaceChange::SurfaceChangeCase::kLayerStack);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptHiddenFlagUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::hiddenFlagUpdate,
- SurfaceChange::SurfaceChangeCase::kHiddenFlag);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptOpaqueFlagUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::opaqueFlagUpdate,
- SurfaceChange::SurfaceChangeCase::kOpaqueFlag);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptSecureFlagUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::secureFlagUpdate,
- SurfaceChange::SurfaceChangeCase::kSecureFlag);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::reparentUpdate,
- SurfaceChange::SurfaceChangeCase::kReparent);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptRelativeParentUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::relativeParentUpdate,
- SurfaceChange::SurfaceChangeCase::kRelativeParent);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptShadowRadiusUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::shadowRadiusUpdate,
- SurfaceChange::SurfaceChangeCase::kShadowRadius);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptTrustedOverlayUpdateWorks) {
- captureTest(&SurfaceInterceptorTest::trustedOverlayUpdate,
- SurfaceChange::SurfaceChangeCase::kTrustedOverlay);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
- captureTest(&SurfaceInterceptorTest::runAllUpdates,
- &SurfaceInterceptorTest::assertAllUpdatesFound);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptSurfaceCreationWorks) {
- captureTest(&SurfaceInterceptorTest::surfaceCreation,
- Increment::IncrementCase::kSurfaceCreation);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptDisplayCreationWorks) {
- captureTest(&SurfaceInterceptorTest::displayCreation,
- Increment::IncrementCase::kDisplayCreation);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptDisplayDeletionWorks) {
- enableInterceptor();
- runInTransaction(&SurfaceInterceptorTest::displayDeletion);
- disableInterceptor();
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kDisplayDeletion));
-}
-
-// If the interceptor is enabled while buffer updates are being pushed, the interceptor should
-// first create a snapshot of the existing displays and surfaces and then start capturing
-// the buffer updates
-TEST_F(SurfaceInterceptorTest, InterceptWhileBufferUpdatesWorks) {
- setupBackgroundSurface();
- std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
- enableInterceptor();
- disableInterceptor();
- bufferUpdates.join();
-
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- const auto& firstIncrement = capturedTrace.mutable_increment(0);
- ASSERT_EQ(firstIncrement->increment_case(), Increment::IncrementCase::kDisplayCreation);
-}
-}
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index ad03ed3..797a64c 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -35,7 +35,10 @@
return mDelegate->screenshot();
case RenderPath::VIRTUAL_DISPLAY:
- const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ const auto displayToken = ids.empty()
+ ? nullptr
+ : SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
ui::DisplayState displayState;
SurfaceComposerClient::getDisplayState(displayToken, &displayState);
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
deleted file mode 100644
index 06afdb1..0000000
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ /dev/null
@@ -1,65 +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"],
-}
-
-cc_test {
- name: "sffakehwc_test",
- defaults: [
- "android.hardware.graphics.composer3-ndk_shared",
- "surfaceflinger_defaults",
- ],
- test_suites: ["device-tests"],
- srcs: [
- "FakeComposerClient.cpp",
- "FakeComposerService.cpp",
- "FakeComposerUtils.cpp",
- "SFFakeHwc_test.cpp",
- ],
- require_root: true,
- shared_libs: [
- "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.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.graphics.mapper@4.0",
- "android.hardware.power@1.3",
- "android.hardware.power-V2-cpp",
- "libbase",
- "libbinder",
- "libbinder_ndk",
- "libcutils",
- "libfmq",
- "libgui",
- "libhidlbase",
- "liblayers_proto",
- "liblog",
- "libnativewindow",
- "libsync",
- "libtimestats",
- "libui",
- "libutils",
- ],
- 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/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
deleted file mode 100644
index a5cca35..0000000
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ /dev/null
@@ -1,929 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-//#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "FakeComposer"
-
-#include "FakeComposerClient.h"
-
-#include <gui/SurfaceComposerClient.h>
-
-#include <log/log.h>
-
-#include <gtest/gtest.h>
-
-#include <inttypes.h>
-#include <time.h>
-#include <algorithm>
-#include <condition_variable>
-#include <iostream>
-#include <mutex>
-#include <set>
-#include <thread>
-
-constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0);
-
-using namespace sftest;
-
-using android::Condition;
-using android::Mutex;
-
-using Clock = std::chrono::steady_clock;
-using TimePoint = std::chrono::time_point<Clock>;
-
-namespace {
-
-// Internal state of a layer in the HWC API.
-class LayerImpl {
-public:
- LayerImpl() = default;
-
- bool mValid = true;
- RenderState mRenderState;
- uint32_t mZ = 0;
-};
-
-// Struct for storing per frame rectangle state. Contains the render
-// state shared to the test case. Basically a snapshot and a subset of
-// LayerImpl sufficient to re-create the pixels of a layer for the
-// frame.
-struct FrameRect {
-public:
- FrameRect(Layer layer_, const RenderState& state, uint32_t z_)
- : layer(layer_), renderState(state), z(z_) {}
-
- const Layer layer;
- const RenderState renderState;
- const uint32_t z;
-};
-
-// Collection of FrameRects forming one rendered frame. Could store
-// related fences and other data in the future.
-class Frame {
-public:
- Frame() = default;
- std::vector<std::unique_ptr<FrameRect>> rectangles;
-};
-
-class DelayedEventGenerator {
-public:
- explicit DelayedEventGenerator(std::function<void()> onTimerExpired)
- : mOnTimerExpired(onTimerExpired) {
- mThread = std::thread([this]() { loop(); });
- }
-
- ~DelayedEventGenerator() {
- ALOGI("DelayedEventGenerator exiting.");
- {
- std::unique_lock<std::mutex> lock(mMutex);
- mRunning = false;
- mWakeups.clear();
- mCondition.notify_one();
- }
- mThread.join();
- ALOGI("DelayedEventGenerator exited.");
- }
-
- void wakeAfter(std::chrono::nanoseconds waitTime) {
- std::unique_lock<std::mutex> lock(mMutex);
- mWakeups.insert(Clock::now() + waitTime);
- mCondition.notify_one();
- }
-
-private:
- void loop() {
- while (true) {
- // Lock scope
- {
- std::unique_lock<std::mutex> lock(mMutex);
- mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); });
- if (!mRunning && mWakeups.empty()) {
- // This thread should only exit once the destructor has been called and all
- // wakeups have been processed
- return;
- }
-
- // At this point, mWakeups will not be empty
-
- TimePoint target = *(mWakeups.begin());
- auto status = mCondition.wait_until(lock, target);
- while (status == std::cv_status::no_timeout) {
- // This was either a spurious wakeup or another wakeup was added, so grab the
- // oldest point and wait again
- target = *(mWakeups.begin());
- status = mCondition.wait_until(lock, target);
- }
-
- // status must have been timeout, so we can finally clear this point
- mWakeups.erase(target);
- }
- // Callback *without* locks!
- mOnTimerExpired();
- }
- }
-
- std::function<void()> mOnTimerExpired;
- std::thread mThread;
- std::mutex mMutex;
- std::condition_variable mCondition;
- bool mRunning = true;
- std::set<TimePoint> mWakeups;
-};
-
-} // namespace
-
-FakeComposerClient::FakeComposerClient()
- : mEventCallback(nullptr),
- mEventCallback_2_4(nullptr),
- mCurrentConfig(NULL_DISPLAY_CONFIG),
- mVsyncEnabled(false),
- mLayers(),
- mDelayedEventGenerator(
- std::make_unique<DelayedEventGenerator>([this]() { this->requestVSync(); })),
- mSurfaceComposer(nullptr) {}
-
-FakeComposerClient::~FakeComposerClient() {}
-
-bool FakeComposerClient::hasCapability(hwc2_capability_t /*capability*/) {
- return false;
-}
-
-std::string FakeComposerClient::dumpDebugInfo() {
- return {};
-}
-
-void FakeComposerClient::registerEventCallback(EventCallback* callback) {
- ALOGV("registerEventCallback");
- LOG_FATAL_IF(mEventCallback_2_4 != nullptr,
- "already registered using registerEventCallback_2_4");
-
- mEventCallback = callback;
- if (mEventCallback) {
- mEventCallback->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
- }
-}
-
-void FakeComposerClient::unregisterEventCallback() {
- ALOGV("unregisterEventCallback");
- mEventCallback = nullptr;
-}
-
-void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) {
- if (mEventCallback) {
- mEventCallback->onHotplug(display, state);
- } else if (mEventCallback_2_4) {
- mEventCallback_2_4->onHotplug(display, state);
- }
-}
-
-void FakeComposerClient::refreshDisplay(Display display) {
- if (mEventCallback) {
- mEventCallback->onRefresh(display);
- } else if (mEventCallback_2_4) {
- mEventCallback_2_4->onRefresh(display);
- }
-}
-
-uint32_t FakeComposerClient::getMaxVirtualDisplayCount() {
- ALOGV("getMaxVirtualDisplayCount");
- return 1;
-}
-
-V2_1::Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
- V1_0::PixelFormat* /*format*/,
- Display* /*outDisplay*/) {
- ALOGV("createVirtualDisplay");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
- ALOGV("destroyVirtualDisplay");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
- ALOGV("createLayer");
- *outLayer = mLayers.size();
- auto newLayer = std::make_unique<LayerImpl>();
- mLayers.push_back(std::move(newLayer));
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
- ALOGV("destroyLayer");
- mLayers[layer]->mValid = false;
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::getActiveConfig(Display display, Config* outConfig) {
- ALOGV("getActiveConfig");
- if (mMockHal) {
- return mMockHal->getActiveConfig(display, outConfig);
- }
-
- // TODO Assert outConfig != nullptr
-
- // TODO This is my reading of the
- // IComposerClient::getActiveConfig, but returning BAD_CONFIG
- // seems to not fit SurfaceFlinger plans. See version 2 below.
- // if (mCurrentConfig == NULL_DISPLAY_CONFIG) {
- // return V2_1::Error::BAD_CONFIG;
- // }
- //*outConfig = mCurrentConfig;
- *outConfig = 1; // Very special config for you my friend
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
- uint32_t /*height*/,
- V1_0::PixelFormat /*format*/,
- V1_0::Dataspace /*dataspace*/) {
- ALOGV("getClientTargetSupport");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::getColorModes(Display /*display*/,
- hidl_vec<V1_0::ColorMode>* /*outModes*/) {
- ALOGV("getColorModes");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
- V2_1::IComposerClient::Attribute attribute,
- int32_t* outValue) {
- auto tmpError =
- getDisplayAttribute_2_4(display, config,
- static_cast<IComposerClient::Attribute>(attribute), outValue);
- return static_cast<V2_1::Error>(tmpError);
-}
-
-V2_1::Error FakeComposerClient::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
- ALOGV("getDisplayConfigs");
- if (mMockHal) {
- return mMockHal->getDisplayConfigs(display, outConfigs);
- }
-
- // TODO assert display == 1, outConfigs != nullptr
-
- outConfigs->resize(1);
- (*outConfigs)[0] = 1;
-
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
- ALOGV("getDisplayName");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::getDisplayType(Display /*display*/,
- IComposerClient::DisplayType* outType) {
- ALOGV("getDisplayType");
- // TODO: This setting nothing on the output had no effect on initial trials. Is first display
- // assumed to be physical?
- *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
- ALOGV("getDozeSupport");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::getHdrCapabilities(Display /*display*/,
- hidl_vec<V1_0::Hdr>* /*outTypes*/,
- float* /*outMaxLuminance*/,
- float* /*outMaxAverageLuminance*/,
- float* /*outMinLuminance*/) {
- ALOGV("getHdrCapabilities");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setActiveConfig(Display display, Config config) {
- ALOGV("setActiveConfig");
- if (mMockHal) {
- return mMockHal->setActiveConfig(display, config);
- }
- mCurrentConfig = config;
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setColorMode(Display /*display*/, V1_0::ColorMode /*mode*/) {
- ALOGV("setColorMode");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setPowerMode(Display /*display*/,
- V2_1::IComposerClient::PowerMode /*mode*/) {
- ALOGV("setPowerMode");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setVsyncEnabled(Display /*display*/,
- IComposerClient::Vsync enabled) {
- mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
- ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
- int32_t /*hint*/) {
- ALOGV("setColorTransform");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
- int32_t /*acquireFence*/, int32_t /*dataspace*/,
- const std::vector<hwc_rect_t>& /*damage*/) {
- ALOGV("setClientTarget");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
- int32_t /*releaseFence*/) {
- ALOGV("setOutputBuffer");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::validateDisplay(
- Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
- std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
- uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
- std::vector<uint32_t>* /*outRequestMasks*/) {
- ALOGV("validateDisplay");
- // TODO: Assume touching nothing means All Korrekt!
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
- ALOGV("acceptDisplayChanges");
- // Didn't ask for changes because software is omnipotent.
- return V2_1::Error::NONE;
-}
-
-bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
- return a->z <= b->z;
-}
-
-V2_1::Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
- std::vector<Layer>* /*outLayers*/,
- std::vector<int32_t>* /*outReleaseFences*/) {
- ALOGV("presentDisplay");
- // TODO Leaving layers and their fences out for now. Doing so
- // means that we've already processed everything. Important to
- // test that the fences are respected, though. (How?)
-
- std::unique_ptr<Frame> newFrame(new Frame);
- for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
- const LayerImpl& layerImpl = *mLayers[layer];
-
- if (!layerImpl.mValid) continue;
-
- auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
- newFrame->rectangles.push_back(std::move(rect));
- }
- std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
- {
- Mutex::Autolock _l(mStateMutex);
- mFrames.push_back(std::move(newFrame));
- mFramesAvailable.broadcast();
- }
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
- int32_t /*x*/, int32_t /*y*/) {
- ALOGV("setLayerCursorPosition");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer,
- buffer_handle_t buffer, int32_t acquireFence) {
- ALOGV("setLayerBuffer");
- LayerImpl& l = getLayerImpl(layer);
- if (buffer != l.mRenderState.mBuffer) {
- l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
- }
- l.mRenderState.mBuffer = buffer;
- l.mRenderState.mAcquireFence = acquireFence;
-
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
- const std::vector<hwc_rect_t>& /*damage*/) {
- ALOGV("setLayerSurfaceDamage");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
- ALOGV("setLayerBlendMode");
- getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
- IComposerClient::Color color) {
- ALOGV("setLayerColor");
- getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
- getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
- getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
- getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
- int32_t /*type*/) {
- ALOGV("setLayerCompositionType");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
- int32_t /*dataspace*/) {
- ALOGV("setLayerDataspace");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
- const hwc_rect_t& frame) {
- ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
- frame.bottom);
- getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
- ALOGV("setLayerPlaneAlpha");
- getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
- buffer_handle_t /*stream*/) {
- ALOGV("setLayerSidebandStream");
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
- const hwc_frect_t& crop) {
- ALOGV("setLayerSourceCrop");
- getLayerImpl(layer).mRenderState.mSourceCrop = crop;
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer,
- int32_t transform) {
- ALOGV("setLayerTransform");
- getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
- const std::vector<hwc_rect_t>& visible) {
- ALOGV("setLayerVisibleRegion");
- getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
- return V2_1::Error::NONE;
-}
-
-V2_1::Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
- ALOGV("setLayerZOrder");
- getLayerImpl(layer).mZ = z;
- return V2_1::Error::NONE;
-}
-
-// Composer 2.2
-V2_1::Error FakeComposerClient::getPerFrameMetadataKeys(
- Display /*display*/, std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* /*outKeys*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setLayerPerFrameMetadata(
- Display /*display*/, Layer /*layer*/,
- const std::vector<V2_2::IComposerClient::PerFrameMetadata>& /*metadata*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getReadbackBufferAttributes(
- Display /*display*/, graphics::common::V1_1::PixelFormat* /*outFormat*/,
- graphics::common::V1_1::Dataspace* /*outDataspace*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setReadbackBuffer(Display /*display*/,
- const native_handle_t* /*bufferHandle*/,
- android::base::unique_fd /*fenceFd*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getReadbackBufferFence(Display /*display*/,
- android::base::unique_fd* /*outFenceFd*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::createVirtualDisplay_2_2(
- uint32_t /*width*/, uint32_t /*height*/, graphics::common::V1_1::PixelFormat* /*format*/,
- Display* /*outDisplay*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-V2_1::Error FakeComposerClient::getClientTargetSupport_2_2(
- Display /*display*/, uint32_t /*width*/, uint32_t /*height*/,
- graphics::common::V1_1::PixelFormat /*format*/,
- graphics::common::V1_1::Dataspace /*dataspace*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setPowerMode_2_2(Display /*display*/,
- V2_2::IComposerClient::PowerMode /*mode*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setLayerFloatColor(Display /*display*/, Layer /*layer*/,
- V2_2::IComposerClient::FloatColor /*color*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getColorModes_2_2(
- Display /*display*/, hidl_vec<graphics::common::V1_1::ColorMode>* /*outModes*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getRenderIntents(
- Display /*display*/, graphics::common::V1_1::ColorMode /*mode*/,
- std::vector<graphics::common::V1_1::RenderIntent>* /*outIntents*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setColorMode_2_2(Display /*display*/,
- graphics::common::V1_1::ColorMode /*mode*/,
- graphics::common::V1_1::RenderIntent /*intent*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-std::array<float, 16> FakeComposerClient::getDataspaceSaturationMatrix(
- graphics::common::V1_1::Dataspace /*dataspace*/) {
- return {};
-}
-
-// Composer 2.3
-V2_1::Error FakeComposerClient::getPerFrameMetadataKeys_2_3(
- Display /*display*/, std::vector<V2_3::IComposerClient::PerFrameMetadataKey>* /*outKeys*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setColorMode_2_3(Display /*display*/,
- graphics::common::V1_2::ColorMode /*mode*/,
- graphics::common::V1_1::RenderIntent /*intent*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getRenderIntents_2_3(
- Display /*display*/, graphics::common::V1_2::ColorMode /*mode*/,
- std::vector<graphics::common::V1_1::RenderIntent>* /*outIntents*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getColorModes_2_3(
- Display /*display*/, hidl_vec<graphics::common::V1_2::ColorMode>* /*outModes*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getClientTargetSupport_2_3(
- Display /*display*/, uint32_t /*width*/, uint32_t /*height*/,
- graphics::common::V1_2::PixelFormat /*format*/,
- graphics::common::V1_2::Dataspace /*dataspace*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getReadbackBufferAttributes_2_3(
- Display /*display*/, graphics::common::V1_2::PixelFormat* /*outFormat*/,
- graphics::common::V1_2::Dataspace* /*outDataspace*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getHdrCapabilities_2_3(
- Display /*display*/, hidl_vec<graphics::common::V1_2::Hdr>* /*outTypes*/,
- float* /*outMaxLuminance*/, float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setLayerPerFrameMetadata_2_3(
- Display /*display*/, Layer /*layer*/,
- const std::vector<V2_3::IComposerClient::PerFrameMetadata>& /*metadata*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getDisplayIdentificationData(Display /*display*/,
- uint8_t* /*outPort*/,
- std::vector<uint8_t>* /*outData*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setLayerColorTransform(Display /*display*/, Layer /*layer*/,
- const float* /*matrix*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getDisplayedContentSamplingAttributes(
- uint64_t /*display*/, graphics::common::V1_2::PixelFormat& /*format*/,
- graphics::common::V1_2::Dataspace& /*dataspace*/,
- hidl_bitfield<V2_3::IComposerClient::FormatColorComponent>& /*componentMask*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setDisplayedContentSamplingEnabled(
- uint64_t /*display*/, V2_3::IComposerClient::DisplayedContentSampling /*enable*/,
- hidl_bitfield<V2_3::IComposerClient::FormatColorComponent> /*componentMask*/,
- uint64_t /*maxFrames*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getDisplayedContentSample(
- uint64_t /*display*/, uint64_t /*maxFrames*/, uint64_t /*timestamp*/,
- uint64_t& /*frameCount*/, hidl_vec<uint64_t>& /*sampleComponent0*/,
- hidl_vec<uint64_t>& /*sampleComponent1*/, hidl_vec<uint64_t>& /*sampleComponent2*/,
- hidl_vec<uint64_t>& /*sampleComponent3*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getDisplayCapabilities(
- Display /*display*/,
- std::vector<V2_3::IComposerClient::DisplayCapability>* /*outCapabilities*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setLayerPerFrameMetadataBlobs(
- Display /*display*/, Layer /*layer*/,
- std::vector<V2_3::IComposerClient::PerFrameMetadataBlob>& /*blobs*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::getDisplayBrightnessSupport(Display /*display*/,
- bool* /*outSupport*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-V2_1::Error FakeComposerClient::setDisplayBrightness(Display /*display*/, float /*brightness*/) {
- return V2_1::Error::UNSUPPORTED;
-}
-
-// Composer 2.4
-void FakeComposerClient::registerEventCallback_2_4(EventCallback_2_4* callback) {
- ALOGV("registerEventCallback_2_4");
- LOG_FATAL_IF(mEventCallback != nullptr, "already registered using registerEventCallback");
-
- mEventCallback_2_4 = callback;
- if (mEventCallback_2_4) {
- mEventCallback_2_4->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
- }
-}
-
-void FakeComposerClient::unregisterEventCallback_2_4() {
- ALOGV("unregisterEventCallback_2_4");
- mEventCallback_2_4 = nullptr;
-}
-
-V2_4::Error FakeComposerClient::getDisplayCapabilities_2_4(
- Display /*display*/,
- std::vector<V2_4::IComposerClient::DisplayCapability>* /*outCapabilities*/) {
- return V2_4::Error::UNSUPPORTED;
-}
-
-V2_4::Error FakeComposerClient::getDisplayConnectionType(
- Display /*display*/, V2_4::IComposerClient::DisplayConnectionType* /*outType*/) {
- return V2_4::Error::UNSUPPORTED;
-}
-
-V2_4::Error FakeComposerClient::getDisplayAttribute_2_4(Display display, Config config,
- IComposerClient::Attribute attribute,
- int32_t* outValue) {
- ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display),
- static_cast<int>(config), static_cast<int>(attribute), outValue);
- if (mMockHal) {
- return mMockHal->getDisplayAttribute_2_4(display, config, attribute, outValue);
- }
-
- // TODO: SOOO much fun to be had with these alone
- switch (attribute) {
- case IComposerClient::Attribute::WIDTH:
- *outValue = 1920;
- break;
- case IComposerClient::Attribute::HEIGHT:
- *outValue = 1080;
- break;
- case IComposerClient::Attribute::VSYNC_PERIOD:
- *outValue = 1666666666;
- break; // TOOD: Tests break down if lowered to 16ms?
- case IComposerClient::Attribute::DPI_X:
- *outValue = 240;
- break;
- case IComposerClient::Attribute::DPI_Y:
- *outValue = 240;
- break;
- default:
- LOG_ALWAYS_FATAL("Say what!?! New attribute");
- }
-
- return Error::NONE;
-}
-
-V2_4::Error FakeComposerClient::getDisplayVsyncPeriod(Display display,
- V2_4::VsyncPeriodNanos* outVsyncPeriod) {
- ALOGV("getDisplayVsyncPeriod");
- if (mMockHal) {
- return mMockHal->getDisplayVsyncPeriod(display, outVsyncPeriod);
- }
-
- return V2_4::Error::UNSUPPORTED;
-}
-
-V2_4::Error FakeComposerClient::setActiveConfigWithConstraints(
- Display display, Config config,
- const V2_4::IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
- VsyncPeriodChangeTimeline* timeline) {
- ALOGV("setActiveConfigWithConstraints");
- if (mMockHal) {
- return mMockHal->setActiveConfigWithConstraints(display, config,
- vsyncPeriodChangeConstraints, timeline);
- }
- return V2_4::Error::UNSUPPORTED;
-}
-
-V2_4::Error FakeComposerClient::setAutoLowLatencyMode(Display, bool) {
- ALOGV("setAutoLowLatencyMode");
- return V2_4::Error::UNSUPPORTED;
-}
-
-V2_4::Error FakeComposerClient::getSupportedContentTypes(
- Display, std::vector<IComposerClient::ContentType>*) {
- ALOGV("getSupportedContentTypes");
- return V2_4::Error::UNSUPPORTED;
-}
-
-V2_4::Error FakeComposerClient::setContentType(Display, IComposerClient::ContentType) {
- ALOGV("setContentType");
- return V2_4::Error::UNSUPPORTED;
-}
-
-V2_4::Error FakeComposerClient::validateDisplay_2_4(
- Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
- std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
- uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
- std::vector<uint32_t>* /*outRequestMasks*/,
- IComposerClient::ClientTargetProperty* /*outClientTargetProperty*/) {
- return V2_4::Error::NONE;
-}
-
-V2_4::Error FakeComposerClient::setLayerGenericMetadata(Display, Layer, const std::string&, bool,
- const std::vector<uint8_t>&) {
- ALOGV("setLayerGenericMetadata");
- return V2_4::Error::UNSUPPORTED;
-}
-
-V2_4::Error FakeComposerClient::getLayerGenericMetadataKeys(
- std::vector<IComposerClient::LayerGenericMetadataKey>*) {
- ALOGV("getLayerGenericMetadataKeys");
- return V2_4::Error::UNSUPPORTED;
-}
-
-//////////////////////////////////////////////////////////////////
-
-void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
- if (mEventCallback || mEventCallback_2_4) {
- uint64_t timestamp = vsyncTime;
- ALOGV("Vsync");
- if (timestamp == 0) {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
- }
- if (mSurfaceComposer != nullptr) {
- mSurfaceComposer->injectVSync(timestamp);
- } else if (mEventCallback) {
- mEventCallback->onVsync(PRIMARY_DISPLAY, timestamp);
- } else {
- mEventCallback_2_4->onVsync_2_4(PRIMARY_DISPLAY, timestamp, 16'666'666);
- }
- }
-}
-
-void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) {
- mDelayedEventGenerator->wakeAfter(wait);
-}
-
-LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) {
- // TODO Change these to an internal state check that can be
- // invoked from the gtest? GTest macros do not seem all that safe
- // when used outside the test class
- EXPECT_GE(handle, static_cast<Layer>(0));
- EXPECT_LT(handle, mLayers.size());
- return *(mLayers[handle]);
-}
-
-int FakeComposerClient::getFrameCount() const {
- return mFrames.size();
-}
-
-static std::vector<RenderState> extractRenderState(
- const std::vector<std::unique_ptr<FrameRect>>& internalRects) {
- std::vector<RenderState> result;
- result.reserve(internalRects.size());
- for (const std::unique_ptr<FrameRect>& rect : internalRects) {
- result.push_back(rect->renderState);
- }
- return result;
-}
-
-std::vector<RenderState> FakeComposerClient::getFrameRects(int frame) const {
- Mutex::Autolock _l(mStateMutex);
- return extractRenderState(mFrames[frame]->rectangles);
-}
-
-std::vector<RenderState> FakeComposerClient::getLatestFrame() const {
- Mutex::Autolock _l(mStateMutex);
- return extractRenderState(mFrames[mFrames.size() - 1]->rectangles);
-}
-
-void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) {
- int currentFrame = 0;
- {
- Mutex::Autolock _l(mStateMutex); // I hope this is ok...
- currentFrame = static_cast<int>(mFrames.size());
- requestVSync();
- }
- waitUntilFrame(currentFrame + 1, maxWait);
-}
-
-void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const {
- Mutex::Autolock _l(mStateMutex);
- while (mFrames.size() < static_cast<size_t>(targetFrame)) {
- android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count());
- if (result == android::TIMED_OUT) {
- ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame,
- mFrames.size(), maxWait.count());
- return;
- }
- }
-}
-
-void FakeComposerClient::clearFrames() {
- Mutex::Autolock _l(mStateMutex);
- mFrames.clear();
- for (const std::unique_ptr<LayerImpl>& layer : mLayers) {
- if (layer->mValid) {
- layer->mRenderState.mSwapCount = 0;
- }
- }
-}
-
-void FakeComposerClient::onSurfaceFlingerStart() {
- mSurfaceComposer = nullptr;
- do {
- mSurfaceComposer = android::sp<android::SurfaceComposerClient>::make();
- android::status_t initResult = mSurfaceComposer->initCheck();
- if (initResult != android::NO_ERROR) {
- ALOGD("Init result: %d", initResult);
- mSurfaceComposer = nullptr;
- std::this_thread::sleep_for(10ms);
- }
- } while (mSurfaceComposer == nullptr);
- ALOGD("SurfaceComposerClient created");
- mSurfaceComposer->enableVSyncInjections(true);
-}
-
-void FakeComposerClient::onSurfaceFlingerStop() {
- mSurfaceComposer->enableVSyncInjections(false);
- mSurfaceComposer->dispose();
- mSurfaceComposer.clear();
-}
-
-// Includes destroyed layers, stored in order of creation.
-int FakeComposerClient::getLayerCount() const {
- return mLayers.size();
-}
-
-Layer FakeComposerClient::getLayer(size_t index) const {
- // NOTE: If/when passing calls through to actual implementation,
- // this might get more involving.
- return static_cast<Layer>(index);
-}
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
deleted file mode 100644
index 600e765..0000000
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright 2017 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 <chrono>
-
-#include <composer-hal/2.1/ComposerClient.h>
-#include <composer-hal/2.2/ComposerClient.h>
-#include <composer-hal/2.3/ComposerClient.h>
-#include <composer-hal/2.4/ComposerClient.h>
-#include <utils/Condition.h>
-
-#include "MockComposerHal.h"
-#include "RenderState.h"
-
-using namespace android::hardware::graphics::common;
-using namespace android::hardware::graphics::composer;
-using namespace android::hardware::graphics::composer::V2_4;
-using namespace android::hardware::graphics::composer::V2_4::hal;
-using namespace android::hardware;
-using namespace std::chrono_literals;
-
-namespace {
-class LayerImpl;
-class Frame;
-class DelayedEventGenerator;
-} // namespace
-
-namespace android {
-class SurfaceComposerClient;
-} // namespace android
-
-namespace sftest {
-// NOTE: The ID's need to be exactly these. VR composer and parts of
-// the SurfaceFlinger assume the display IDs to have these values
-// despite the enum being documented as a display type.
-// TODO: Reference to actual documentation
-constexpr Display PRIMARY_DISPLAY = static_cast<Display>(HWC_DISPLAY_PRIMARY);
-constexpr Display EXTERNAL_DISPLAY = static_cast<Display>(HWC_DISPLAY_EXTERNAL);
-
-class FakeComposerClient : public ComposerHal {
-public:
- FakeComposerClient();
- virtual ~FakeComposerClient();
-
- void setMockHal(MockComposerHal* mockHal) { mMockHal = mockHal; }
-
- bool hasCapability(hwc2_capability_t capability) override;
-
- std::string dumpDebugInfo() override;
- void registerEventCallback(EventCallback* callback) override;
- void unregisterEventCallback() override;
-
- uint32_t getMaxVirtualDisplayCount() override;
- V2_1::Error createVirtualDisplay(uint32_t width, uint32_t height, V1_0::PixelFormat* format,
- Display* outDisplay) override;
- V2_1::Error destroyVirtualDisplay(Display display) override;
- V2_1::Error createLayer(Display display, Layer* outLayer) override;
- V2_1::Error destroyLayer(Display display, Layer layer) override;
-
- V2_1::Error getActiveConfig(Display display, Config* outConfig) override;
- V2_1::Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
- V1_0::PixelFormat format,
- V1_0::Dataspace dataspace) override;
- V2_1::Error getColorModes(Display display, hidl_vec<V1_0::ColorMode>* outModes) override;
- V2_1::Error getDisplayAttribute(Display display, Config config,
- V2_1::IComposerClient::Attribute attribute,
- int32_t* outValue) override;
- V2_1::Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
- V2_1::Error getDisplayName(Display display, hidl_string* outName) override;
- V2_1::Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
- V2_1::Error getDozeSupport(Display display, bool* outSupport) override;
- V2_1::Error getHdrCapabilities(Display display, hidl_vec<V1_0::Hdr>* outTypes,
- float* outMaxLuminance, float* outMaxAverageLuminance,
- float* outMinLuminance) override;
-
- V2_1::Error setActiveConfig(Display display, Config config) override;
- V2_1::Error setColorMode(Display display, V1_0::ColorMode mode) override;
- V2_1::Error setPowerMode(Display display, V2_1::IComposerClient::PowerMode mode) override;
- V2_1::Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
-
- V2_1::Error setColorTransform(Display display, const float* matrix, int32_t hint) override;
- V2_1::Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
- int32_t dataspace, const std::vector<hwc_rect_t>& damage) override;
- V2_1::Error setOutputBuffer(Display display, buffer_handle_t buffer,
- int32_t releaseFence) override;
- V2_1::Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks) override;
- V2_1::Error acceptDisplayChanges(Display display) override;
- V2_1::Error presentDisplay(Display display, int32_t* outPresentFence,
- std::vector<Layer>* outLayers,
- std::vector<int32_t>* outReleaseFences) override;
-
- V2_1::Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
- V2_1::Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
- int32_t acquireFence) override;
- V2_1::Error setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage) override;
- V2_1::Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
- V2_1::Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override;
- V2_1::Error setLayerCompositionType(Display display, Layer layer, int32_t type) override;
- V2_1::Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override;
- V2_1::Error setLayerDisplayFrame(Display display, Layer layer,
- const hwc_rect_t& frame) override;
- V2_1::Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
- V2_1::Error setLayerSidebandStream(Display display, Layer layer,
- buffer_handle_t stream) override;
- V2_1::Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override;
- V2_1::Error setLayerTransform(Display display, Layer layer, int32_t transform) override;
- V2_1::Error setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible) override;
- V2_1::Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
-
- // Composer 2.2
- V2_1::Error getPerFrameMetadataKeys(
- Display display,
- std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* outKeys) override;
- V2_1::Error setLayerPerFrameMetadata(
- Display display, Layer layer,
- const std::vector<V2_2::IComposerClient::PerFrameMetadata>& metadata) override;
-
- V2_1::Error getReadbackBufferAttributes(
- Display display, graphics::common::V1_1::PixelFormat* outFormat,
- graphics::common::V1_1::Dataspace* outDataspace) override;
- V2_1::Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
- android::base::unique_fd fenceFd) override;
- V2_1::Error getReadbackBufferFence(Display display,
- android::base::unique_fd* outFenceFd) override;
- V2_1::Error createVirtualDisplay_2_2(uint32_t width, uint32_t height,
- graphics::common::V1_1::PixelFormat* format,
- Display* outDisplay) override;
- V2_1::Error getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height,
- graphics::common::V1_1::PixelFormat format,
- graphics::common::V1_1::Dataspace dataspace) override;
- V2_1::Error setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) override;
-
- V2_1::Error setLayerFloatColor(Display display, Layer layer,
- V2_2::IComposerClient::FloatColor color) override;
-
- V2_1::Error getColorModes_2_2(Display display,
- hidl_vec<graphics::common::V1_1::ColorMode>* outModes) override;
- V2_1::Error getRenderIntents(
- Display display, graphics::common::V1_1::ColorMode mode,
- std::vector<graphics::common::V1_1::RenderIntent>* outIntents) override;
- V2_1::Error setColorMode_2_2(Display display, graphics::common::V1_1::ColorMode mode,
- graphics::common::V1_1::RenderIntent intent) override;
-
- std::array<float, 16> getDataspaceSaturationMatrix(
- graphics::common::V1_1::Dataspace dataspace) override;
-
- // Composer 2.3
- V2_1::Error getPerFrameMetadataKeys_2_3(
- Display display,
- std::vector<V2_3::IComposerClient::PerFrameMetadataKey>* outKeys) override;
-
- V2_1::Error setColorMode_2_3(Display display, graphics::common::V1_2::ColorMode mode,
- graphics::common::V1_1::RenderIntent intent) override;
-
- V2_1::Error getRenderIntents_2_3(
- Display display, graphics::common::V1_2::ColorMode mode,
- std::vector<graphics::common::V1_1::RenderIntent>* outIntents) override;
-
- V2_1::Error getColorModes_2_3(Display display,
- hidl_vec<graphics::common::V1_2::ColorMode>* outModes) override;
-
- V2_1::Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
- graphics::common::V1_2::PixelFormat format,
- graphics::common::V1_2::Dataspace dataspace) override;
- V2_1::Error getReadbackBufferAttributes_2_3(
- Display display, graphics::common::V1_2::PixelFormat* outFormat,
- graphics::common::V1_2::Dataspace* outDataspace) override;
- V2_1::Error getHdrCapabilities_2_3(Display display,
- hidl_vec<graphics::common::V1_2::Hdr>* outTypes,
- float* outMaxLuminance, float* outMaxAverageLuminance,
- float* outMinLuminance) override;
- V2_1::Error setLayerPerFrameMetadata_2_3(
- Display display, Layer layer,
- const std::vector<V2_3::IComposerClient::PerFrameMetadata>& metadata) override;
- V2_1::Error getDisplayIdentificationData(Display display, uint8_t* outPort,
- std::vector<uint8_t>* outData) override;
- V2_1::Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override;
- V2_1::Error getDisplayedContentSamplingAttributes(
- uint64_t display, graphics::common::V1_2::PixelFormat& format,
- graphics::common::V1_2::Dataspace& dataspace,
- hidl_bitfield<V2_3::IComposerClient::FormatColorComponent>& componentMask) override;
- V2_1::Error setDisplayedContentSamplingEnabled(
- uint64_t display, V2_3::IComposerClient::DisplayedContentSampling enable,
- hidl_bitfield<V2_3::IComposerClient::FormatColorComponent> componentMask,
- uint64_t maxFrames) override;
- V2_1::Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
- uint64_t& frameCount,
- hidl_vec<uint64_t>& sampleComponent0,
- hidl_vec<uint64_t>& sampleComponent1,
- hidl_vec<uint64_t>& sampleComponent2,
- hidl_vec<uint64_t>& sampleComponent3) override;
- V2_1::Error getDisplayCapabilities(
- Display display,
- std::vector<V2_3::IComposerClient::DisplayCapability>* outCapabilities) override;
- V2_1::Error setLayerPerFrameMetadataBlobs(
- Display display, Layer layer,
- std::vector<V2_3::IComposerClient::PerFrameMetadataBlob>& blobs) override;
- V2_1::Error getDisplayBrightnessSupport(Display display, bool* outSupport) override;
- V2_1::Error setDisplayBrightness(Display display, float brightness) override;
-
- // Composer 2.4
- void registerEventCallback_2_4(EventCallback_2_4* callback) override;
-
- void unregisterEventCallback_2_4() override;
-
- V2_4::Error getDisplayCapabilities_2_4(
- Display display,
- std::vector<V2_4::IComposerClient::DisplayCapability>* outCapabilities) override;
- V2_4::Error getDisplayConnectionType(
- Display display, V2_4::IComposerClient::DisplayConnectionType* outType) override;
- V2_4::Error getDisplayAttribute_2_4(Display display, Config config,
- IComposerClient::Attribute attribute,
- int32_t* outValue) override;
- V2_4::Error getDisplayVsyncPeriod(Display display,
- V2_4::VsyncPeriodNanos* outVsyncPeriod) override;
- V2_4::Error setActiveConfigWithConstraints(
- Display display, Config config,
- const V2_4::IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
- VsyncPeriodChangeTimeline* outTimeline) override;
- V2_4::Error setAutoLowLatencyMode(Display display, bool on) override;
- V2_4::Error getSupportedContentTypes(
- Display display,
- std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
- V2_4::Error setContentType(Display display, IComposerClient::ContentType type) override;
- V2_4::Error validateDisplay_2_4(
- Display display, std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks,
- IComposerClient::ClientTargetProperty* outClientTargetProperty) 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;
-
- void setClient(ComposerClient* client);
-
- void requestVSync(uint64_t vsyncTime = 0);
- // We don't want tests hanging, so always use a timeout. Remember
- // to always check the number of frames with test ASSERT_!
- // Wait until next frame is rendered after requesting vsync.
- void runVSyncAndWait(std::chrono::nanoseconds maxWait = 100ms);
- void runVSyncAfter(std::chrono::nanoseconds wait);
-
- int getFrameCount() const;
- // We don't want tests hanging, so always use a timeout. Remember
- // to always check the number of frames with test ASSERT_!
- void waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait = 100ms) const;
- std::vector<RenderState> getFrameRects(int frame) const;
- std::vector<RenderState> getLatestFrame() const;
- void clearFrames();
-
- void onSurfaceFlingerStart();
- void onSurfaceFlingerStop();
-
- int getLayerCount() const;
- Layer getLayer(size_t index) const;
-
- void hotplugDisplay(Display display, IComposerCallback::Connection state);
- void refreshDisplay(Display display);
-
-private:
- LayerImpl& getLayerImpl(Layer handle);
-
- EventCallback* mEventCallback;
- EventCallback_2_4* mEventCallback_2_4;
- Config mCurrentConfig;
- bool mVsyncEnabled;
- std::vector<std::unique_ptr<LayerImpl>> mLayers;
- std::vector<std::unique_ptr<Frame>> mFrames;
- // Using a pointer to hide the implementation into the CPP file.
- std::unique_ptr<DelayedEventGenerator> mDelayedEventGenerator;
- android::sp<android::SurfaceComposerClient> mSurfaceComposer; // For VSync injections
- mutable android::Mutex mStateMutex;
- mutable android::Condition mFramesAvailable;
-
- MockComposerHal* mMockHal = nullptr;
-};
-
-} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
deleted file mode 100644
index c656eed..0000000
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "FakeHwcService"
-#include <log/log.h>
-
-#include "FakeComposerService.h"
-
-using namespace android::hardware;
-using namespace android::hardware::graphics::composer;
-
-namespace sftest {
-
-FakeComposerService_2_1::FakeComposerService_2_1(android::sp<ComposerClient>& client)
- : mClient(client) {}
-
-FakeComposerService_2_1::~FakeComposerService_2_1() {
- ALOGI("Maybe killing client %p", mClient.get());
- // Rely on sp to kill the client.
-}
-
-Return<void> FakeComposerService_2_1::getCapabilities(getCapabilities_cb hidl_cb) {
- ALOGI("FakeComposerService::getCapabilities");
- hidl_cb(hidl_vec<Capability>());
- return Void();
-}
-
-Return<void> FakeComposerService_2_1::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
- ALOGI("FakeComposerService::dumpDebugInfo");
- hidl_cb(hidl_string());
- return Void();
-}
-
-Return<void> FakeComposerService_2_1::createClient(createClient_cb hidl_cb) {
- ALOGI("FakeComposerService::createClient %p", mClient.get());
- if (!mClient->init()) {
- LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
- }
- hidl_cb(V2_1::Error::NONE, mClient);
- return Void();
-}
-
-FakeComposerService_2_2::FakeComposerService_2_2(android::sp<ComposerClient>& client)
- : mClient(client) {}
-
-FakeComposerService_2_2::~FakeComposerService_2_2() {
- ALOGI("Maybe killing client %p", mClient.get());
- // Rely on sp to kill the client.
-}
-
-Return<void> FakeComposerService_2_2::getCapabilities(getCapabilities_cb hidl_cb) {
- ALOGI("FakeComposerService::getCapabilities");
- hidl_cb(hidl_vec<Capability>());
- return Void();
-}
-
-Return<void> FakeComposerService_2_2::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
- ALOGI("FakeComposerService::dumpDebugInfo");
- hidl_cb(hidl_string());
- return Void();
-}
-
-Return<void> FakeComposerService_2_2::createClient(createClient_cb hidl_cb) {
- ALOGI("FakeComposerService::createClient %p", mClient.get());
- if (!mClient->init()) {
- LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
- }
- hidl_cb(V2_1::Error::NONE, mClient);
- return Void();
-}
-
-FakeComposerService_2_3::FakeComposerService_2_3(android::sp<ComposerClient>& client)
- : mClient(client) {}
-
-FakeComposerService_2_3::~FakeComposerService_2_3() {
- ALOGI("Maybe killing client %p", mClient.get());
- // Rely on sp to kill the client.
-}
-
-Return<void> FakeComposerService_2_3::getCapabilities(getCapabilities_cb hidl_cb) {
- ALOGI("FakeComposerService::getCapabilities");
- hidl_cb(hidl_vec<Capability>());
- return Void();
-}
-
-Return<void> FakeComposerService_2_3::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
- ALOGI("FakeComposerService::dumpDebugInfo");
- hidl_cb(hidl_string());
- return Void();
-}
-
-Return<void> FakeComposerService_2_3::createClient(createClient_cb hidl_cb) {
- LOG_ALWAYS_FATAL("createClient called on FakeComposerService_2_3");
- if (!mClient->init()) {
- LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
- }
- hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
- return Void();
-}
-
-Return<void> FakeComposerService_2_3::createClient_2_3(createClient_2_3_cb hidl_cb) {
- ALOGI("FakeComposerService_2_3::createClient_2_3 %p", mClient.get());
- if (!mClient->init()) {
- LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
- }
- hidl_cb(V2_1::Error::NONE, mClient);
- return Void();
-}
-
-FakeComposerService_2_4::FakeComposerService_2_4(android::sp<ComposerClient>& client)
- : mClient(client) {}
-
-FakeComposerService_2_4::~FakeComposerService_2_4() {
- ALOGI("Maybe killing client %p", mClient.get());
- // Rely on sp to kill the client.
-}
-
-Return<void> FakeComposerService_2_4::getCapabilities(getCapabilities_cb hidl_cb) {
- ALOGI("FakeComposerService::getCapabilities");
- hidl_cb(hidl_vec<Capability>());
- return Void();
-}
-
-Return<void> FakeComposerService_2_4::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
- ALOGI("FakeComposerService::dumpDebugInfo");
- hidl_cb(hidl_string());
- return Void();
-}
-
-Return<void> FakeComposerService_2_4::createClient(createClient_cb hidl_cb) {
- LOG_ALWAYS_FATAL("createClient called on FakeComposerService_2_4");
- if (!mClient->init()) {
- LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
- }
- hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
- return Void();
-}
-
-Return<void> FakeComposerService_2_4::createClient_2_3(createClient_2_3_cb hidl_cb) {
- LOG_ALWAYS_FATAL("createClient_2_3 called on FakeComposerService_2_4");
- if (!mClient->init()) {
- LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
- }
- hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
- return Void();
-}
-
-Return<void> FakeComposerService_2_4::createClient_2_4(createClient_2_4_cb hidl_cb) {
- ALOGI("FakeComposerService_2_4::createClient_2_4 %p", mClient.get());
- if (!mClient->init()) {
- LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
- }
- hidl_cb(V2_4::Error::NONE, mClient);
- return Void();
-}
-
-} // namespace sftest
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
deleted file mode 100644
index 47f970f..0000000
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/graphics/composer/2.4/IComposer.h>
-#include <composer-hal/2.1/ComposerClient.h>
-#include <composer-hal/2.2/ComposerClient.h>
-#include <composer-hal/2.3/ComposerClient.h>
-#include <composer-hal/2.4/ComposerClient.h>
-
-using android::hardware::Return;
-
-using ComposerClient = android::hardware::graphics::composer::V2_4::hal::ComposerClient;
-
-namespace sftest {
-
-using IComposer_2_1 = android::hardware::graphics::composer::V2_1::IComposer;
-
-class FakeComposerService_2_1 : public IComposer_2_1 {
-public:
- explicit FakeComposerService_2_1(android::sp<ComposerClient>& client);
- virtual ~FakeComposerService_2_1();
-
- Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
- Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
- Return<void> createClient(createClient_cb hidl_cb) override;
-
-private:
- android::sp<ComposerClient> mClient;
-};
-
-using IComposer_2_2 = android::hardware::graphics::composer::V2_2::IComposer;
-class FakeComposerService_2_2 : public IComposer_2_2 {
-public:
- explicit FakeComposerService_2_2(android::sp<ComposerClient>& client);
- virtual ~FakeComposerService_2_2();
-
- Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
- Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
- Return<void> createClient(createClient_cb hidl_cb) override;
-
-private:
- android::sp<ComposerClient> mClient;
-};
-
-using IComposer_2_3 = android::hardware::graphics::composer::V2_3::IComposer;
-class FakeComposerService_2_3 : public IComposer_2_3 {
-public:
- explicit FakeComposerService_2_3(android::sp<ComposerClient>& client);
- virtual ~FakeComposerService_2_3();
-
- Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
- Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
- Return<void> createClient(createClient_cb hidl_cb) override;
- Return<void> createClient_2_3(createClient_2_3_cb hidl_cb) override;
-
-private:
- android::sp<ComposerClient> mClient;
-};
-
-using IComposer_2_4 = android::hardware::graphics::composer::V2_4::IComposer;
-
-class FakeComposerService_2_4 : public IComposer_2_4 {
-public:
- explicit FakeComposerService_2_4(android::sp<ComposerClient>& client);
- virtual ~FakeComposerService_2_4();
-
- Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
- Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
- Return<void> createClient(createClient_cb hidl_cb) override;
- Return<void> createClient_2_3(createClient_2_3_cb hidl_cb) override;
- Return<void> createClient_2_4(createClient_2_4_cb hidl_cb) override;
-
-private:
- android::sp<ComposerClient> mClient;
-};
-
-} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
deleted file mode 100644
index 1cea25a..0000000
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "FakeHwcUtil"
-#include <log/log.h>
-
-#include "FakeComposerUtils.h"
-#include "RenderState.h"
-
-#include "SurfaceFlinger.h" // Get the name of the service...
-
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-#include <hidl/ServiceManagement.h>
-
-#include <iomanip>
-#include <thread>
-
-using android::String16;
-using android::sp;
-using namespace std::chrono_literals;
-using namespace sftest;
-using std::setw;
-
-namespace sftest {
-
-// clang-format off
-inline void printSourceRectAligned(::std::ostream& os, const hwc_frect_t& sourceRect, int align) {
- os << std::fixed << std::setprecision(1) << "("
- << setw(align) << sourceRect.left << setw(0) << ","
- << setw(align) << sourceRect.top << setw(0) << ","
- << setw(align) << sourceRect.right << setw(0) << ","
- << setw(align) << sourceRect.bottom << setw(0) << ")";
-}
-
-inline void printDisplayRectAligned(::std::ostream& os, const hwc_rect_t& displayRect, int align) {
- os << "("
- << setw(align) << displayRect.left << setw(0) << ","
- << setw(align) << displayRect.top << setw(0) << ","
- << setw(align) << displayRect.right << setw(0) << ","
- << setw(align) << displayRect.bottom << setw(0) << ")";
-}
-// clang-format on
-
-inline ::std::ostream& operator<<(::std::ostream& os, const sftest::RenderState& state) {
- printSourceRectAligned(os, state.mSourceCrop, 7);
- os << "->";
- printDisplayRectAligned(os, state.mDisplayFrame, 5);
- return os << " Swaps:" << state.mSwapCount << " Alpha:" << std::setprecision(3)
- << state.mPlaneAlpha << " Xform:" << state.mTransform;
-}
-
-// Helper for verifying the parts of the RenderState
-template <typename T>
-bool valuesMatch(::testing::AssertionResult& message, const T& ref, const T& val,
- const char* name) {
- if (ref != val) {
- message = message << "Expected " << name << ":" << ref << ", got:" << val << ".";
- return false;
- }
- return true;
-}
-
-::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val) {
- // TODO: Message could start as success and be assigned as failure.
- // Only problem is that utility assumes it to be failure and just adds stuff. Would
- // need still special case the initial failure in the utility?
- // TODO: ... or would it be possible to break this back to gtest primitives?
- ::testing::AssertionResult message = ::testing::AssertionFailure();
- bool passes = true;
-
- // The work here is mostly about providing good log strings for differences
- passes &= valuesMatch(message, ref.mDisplayFrame, val.mDisplayFrame, "display frame");
- passes &= valuesMatch(message, ref.mPlaneAlpha, val.mPlaneAlpha, "alpha");
- passes &= valuesMatch(message, ref.mSwapCount, val.mSwapCount, "swap count");
- passes &= valuesMatch(message, ref.mSourceCrop, val.mSourceCrop, "source crop");
- // ... add more
- if (passes) {
- return ::testing::AssertionSuccess();
- }
- return message;
-}
-
-::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
- const std::vector<RenderState>& val) {
- ::testing::AssertionResult message = ::testing::AssertionFailure();
- bool passed = true;
- if (ref.size() != val.size()) {
- message << "Expected " << ref.size() << " rects, got " << val.size() << ".";
- passed = false;
- }
- for (size_t rectIndex = 0; rectIndex < std::min(ref.size(), val.size()); rectIndex++) {
- ::testing::AssertionResult rectResult = rectsAreSame(ref[rectIndex], val[rectIndex]);
- if (rectResult == false) {
- message << "First different rect at " << rectIndex << ": " << rectResult.message();
- passed = false;
- break;
- }
- }
-
- if (passed) {
- return ::testing::AssertionSuccess();
- } else {
- message << "\nReference:";
- for (auto state = ref.begin(); state != ref.end(); ++state) {
- message << "\n" << *state;
- }
- message << "\nActual:";
- for (auto state = val.begin(); state != val.end(); ++state) {
- message << "\n" << *state;
- }
- }
- return message;
-}
-
-void startSurfaceFlinger() {
- ALOGI("Start SurfaceFlinger");
- system("start surfaceflinger");
-
- sp<android::IServiceManager> sm(android::defaultServiceManager());
- sp<android::IBinder> sf;
- while (sf == nullptr) {
- std::this_thread::sleep_for(10ms);
- sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
- }
- ALOGV("SurfaceFlinger running");
-}
-
-void stopSurfaceFlinger() {
- ALOGI("Stop SurfaceFlinger");
- system("stop surfaceflinger");
- sp<android::IServiceManager> sm(android::defaultServiceManager());
- sp<android::IBinder> sf;
- while (sf != nullptr) {
- std::this_thread::sleep_for(10ms);
- sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
- }
- ALOGV("SurfaceFlinger stopped");
-}
-
-////////////////////////////////////////////////
-
-void FakeHwcEnvironment::SetUp() {
- ALOGI("Test env setup");
- system("setenforce 0");
- system("stop");
- property_set("debug.sf.nobootanimation", "1");
- {
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.sf.nobootanimation", value, "0");
- LOG_FATAL_IF(atoi(value) != 1, "boot skip not set");
- }
- // TODO: Try registering the mock as the default service instead.
- property_set("debug.sf.hwc_service_name", "mock");
-
- // This allows tests/SF to register/load a HIDL service not listed in manifest files.
- android::hardware::details::setTrebleTestingOverride(true);
- property_set("debug.sf.treble_testing_override", "true");
-}
-
-void FakeHwcEnvironment::TearDown() {
- ALOGI("Test env tear down");
- system("stop");
- // Wait for mock call signaling teardown?
- property_set("debug.sf.nobootanimation", "0");
- property_set("debug.sf.hwc_service_name", "default");
- system("setenforce 1");
- ALOGI("Test env tear down - done");
-}
-
-} // namespace sftest
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
deleted file mode 100644
index 383a111..0000000
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2017 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 "FakeComposerClient.h"
-
-#include <gui/SurfaceComposerClient.h>
-#include <log/log.h>
-#include <gtest/gtest.h>
-
-// clang-format off
-// Note: This needs to reside in the global namespace for the GTest to use it
-inline ::std::ostream& operator<<(::std::ostream& os, const hwc_rect_t& rect) {
- return os << "(" << rect.left << ","
- << rect.top << ","
- << rect.right << ","
- << rect.bottom << ")";
-}
-
-inline ::std::ostream& operator<<(::std::ostream& os, const hwc_frect_t& rect) {
- return os << "(" << rect.left << ","
- << rect.top << ","
- << rect.right << ","
- << rect.bottom << ")";
-}
-// clang-format on
-
-namespace sftest {
-
-class RenderState;
-
-// clang-format off
-inline bool operator==(const hwc_rect_t& a, const hwc_rect_t& b) {
- return a.top == b.top &&
- a.left == b.left &&
- a.bottom == b.bottom &&
- a.right == b.right;
-}
-
-inline bool operator==(const hwc_frect_t& a, const hwc_frect_t& b) {
- return a.top == b.top &&
- a.left == b.left &&
- a.bottom == b.bottom &&
- a.right == b.right;
-}
-// clang-format on
-
-inline bool operator!=(const hwc_rect_t& a, const hwc_rect_t& b) {
- return !(a == b);
-}
-
-inline bool operator!=(const hwc_frect_t& a, const hwc_frect_t& b) {
- return !(a == b);
-}
-
-::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val);
-::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
- const std::vector<RenderState>& val);
-
-void startSurfaceFlinger();
-void stopSurfaceFlinger();
-
-class FakeHwcEnvironment : public ::testing::Environment {
-public:
- virtual ~FakeHwcEnvironment() {}
- void SetUp() override;
- void TearDown() override;
-};
-
-/*
- * All surface state changes are supposed to happen inside a global
- * transaction. TransactionScope object at the beginning of
- * scope automates the process. The resulting scope gives a visual cue
- * on the span of the transaction as well.
- *
- * Closing the transaction is synchronous, i.e., it waits for
- * SurfaceFlinger to composite one frame. Now, the FakeComposerClient
- * is built to explicitly request vsyncs one at the time. A delayed
- * request must be made before closing the transaction or the test
- * thread stalls until SurfaceFlinger does an emergency vsync by
- * itself. TransactionScope encapsulates this vsync magic.
- */
-class TransactionScope : public android::SurfaceComposerClient::Transaction {
-public:
- explicit TransactionScope(FakeComposerClient& composer) : Transaction(), mComposer(composer) {}
-
- ~TransactionScope() {
- int frameCount = mComposer.getFrameCount();
- mComposer.runVSyncAfter(1ms);
- LOG_ALWAYS_FATAL_IF(android::NO_ERROR != apply());
- // Make sure that exactly one frame has been rendered.
- mComposer.waitUntilFrame(frameCount + 1);
- // LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
- // "Unexpected frame advance. Delta: %d",
- // mComposer.getFrameCount() - frameCount);
- }
-
- FakeComposerClient& mComposer;
-};
-
-} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/MockComposerHal.h b/services/surfaceflinger/tests/fakehwc/MockComposerHal.h
deleted file mode 100644
index 5dc3778..0000000
--- a/services/surfaceflinger/tests/fakehwc/MockComposerHal.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <composer-hal/2.4/ComposerClient.h>
-
-#include <gmock/gmock.h>
-
-using namespace android::hardware::graphics::common;
-using namespace android::hardware::graphics::composer;
-using namespace android::hardware::graphics::composer::V2_4;
-using namespace android::hardware::graphics::composer::V2_4::hal;
-using namespace android::hardware;
-using namespace std::chrono_literals;
-
-namespace sftest {
-
-// Mock class for ComposerHal. Implements only the functions used in the test.
-class MockComposerHal {
-public:
- MOCK_METHOD2(getActiveConfig, V2_1::Error(Display, Config*));
- MOCK_METHOD4(getDisplayAttribute_2_4,
- V2_4::Error(Display, Config, V2_4::IComposerClient::Attribute, int32_t*));
- MOCK_METHOD2(getDisplayConfigs, V2_1::Error(Display, hidl_vec<Config>*));
- MOCK_METHOD2(setActiveConfig, V2_1::Error(Display, Config));
- MOCK_METHOD2(getDisplayVsyncPeriod, V2_4::Error(Display, V2_4::VsyncPeriodNanos*));
- MOCK_METHOD4(setActiveConfigWithConstraints,
- V2_4::Error(Display, Config,
- const V2_4::IComposerClient::VsyncPeriodChangeConstraints&,
- VsyncPeriodChangeTimeline*));
-};
-
-} // namespace sftest
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h
deleted file mode 100644
index 40193f2..0000000
--- a/services/surfaceflinger/tests/fakehwc/RenderState.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2017 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 <vector>
-
-namespace sftest {
-// Description of a rendered rectangle. Should only contain
-// instructions necessary to rasterize the rectangle. The full scene
-// is given as a sorted list of rectangles, bottom layer at index 0.
-class RenderState {
-public:
- RenderState() = default;
- // Default copy-ctor
-
- hwc_rect_t mDisplayFrame = {0, 0, 0, 0};
- hwc_frect_t mSourceCrop = {0.f, 0.f, 0.f, 0.f};
- std::vector<hwc_rect_t> mVisibleRegion;
- hwc2_blend_mode_t mBlendMode = HWC2_BLEND_MODE_NONE;
- buffer_handle_t mBuffer = 0;
- uint32_t mSwapCount = 0; // How many set buffer calls to the layer.
- int32_t mAcquireFence = 0; // Probably should not be here.
- float mPlaneAlpha = 0.f;
- hwc_color_t mLayerColor = {0, 0, 0, 0};
- hwc_transform_t mTransform = static_cast<hwc_transform_t>(0);
-};
-
-} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
deleted file mode 100644
index 1d3401a..0000000
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ /dev/null
@@ -1,1794 +0,0 @@
-/*
- * Copyright (C) 2017 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"
-#pragma clang diagnostic ignored "-Wextra"
-
-// #define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "FakeHwcTest"
-
-#include "FakeComposerClient.h"
-#include "FakeComposerService.h"
-#include "FakeComposerUtils.h"
-#include "MockComposerHal.h"
-
-#include <binder/Parcel.h>
-#include <gui/AidlStatusUtil.h>
-#include <gui/DisplayEventReceiver.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/LayerState.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-
-#include <android/hidl/manager/1.0/IServiceManager.h>
-#include <android/looper.h>
-#include <android/native_window.h>
-#include <binder/ProcessState.h>
-#include <hwbinder/ProcessState.h>
-#include <log/log.h>
-#include <private/gui/ComposerService.h>
-#include <private/gui/ComposerServiceAIDL.h>
-#include <ui/DisplayMode.h>
-#include <ui/DynamicDisplayInfo.h>
-#include <utils/Looper.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <limits>
-#include <thread>
-
-using namespace std::chrono_literals;
-
-using namespace android;
-using namespace android::hardware;
-
-using namespace sftest;
-
-namespace {
-
-// Mock test helpers
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Return;
-using ::testing::SetArgPointee;
-
-using Transaction = SurfaceComposerClient::Transaction;
-using Attribute = V2_4::IComposerClient::Attribute;
-using Display = V2_1::Display;
-
-///////////////////////////////////////////////
-constexpr PhysicalDisplayId physicalIdFromHwcDisplayId(Display hwcId) {
- return PhysicalDisplayId::fromPort(hwcId);
-}
-constexpr PhysicalDisplayId kPrimaryDisplayId = physicalIdFromHwcDisplayId(PRIMARY_DISPLAY);
-constexpr PhysicalDisplayId kExternalDisplayId = physicalIdFromHwcDisplayId(EXTERNAL_DISPLAY);
-
-struct TestColor {
-public:
- uint8_t r;
- uint8_t g;
- uint8_t b;
- uint8_t a;
-};
-
-constexpr static TestColor RED = {195, 63, 63, 255};
-constexpr static TestColor LIGHT_RED = {255, 177, 177, 255};
-constexpr static TestColor GREEN = {63, 195, 63, 255};
-constexpr static TestColor BLUE = {63, 63, 195, 255};
-constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255};
-
-// Fill an RGBA_8888 formatted surface with a single color.
-static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const TestColor& color,
- bool unlock = true) {
- ANativeWindow_Buffer outBuffer;
- sp<Surface> s = sc->getSurface();
- ASSERT_TRUE(s != nullptr);
- ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
- uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
- for (int y = 0; y < outBuffer.height; y++) {
- for (int x = 0; x < outBuffer.width; x++) {
- uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
- pixel[0] = color.r;
- pixel[1] = color.g;
- pixel[2] = color.b;
- pixel[3] = color.a;
- }
- }
- if (unlock) {
- ASSERT_EQ(NO_ERROR, s->unlockAndPost());
- }
-}
-
-inline RenderState makeSimpleRect(int left, int top, int right, int bottom) {
- RenderState res;
- res.mDisplayFrame = hwc_rect_t{left, top, right, bottom};
- res.mPlaneAlpha = 1.0f;
- res.mSwapCount = 0;
- res.mSourceCrop = hwc_frect_t{0.f, 0.f, static_cast<float>(right - left),
- static_cast<float>(bottom - top)};
- return res;
-}
-
-inline RenderState makeSimpleRect(unsigned int left, unsigned int top, unsigned int right,
- unsigned int bottom) {
- EXPECT_LE(left, static_cast<unsigned int>(INT_MAX));
- EXPECT_LE(top, static_cast<unsigned int>(INT_MAX));
- EXPECT_LE(right, static_cast<unsigned int>(INT_MAX));
- EXPECT_LE(bottom, static_cast<unsigned int>(INT_MAX));
- return makeSimpleRect(static_cast<int>(left), static_cast<int>(top), static_cast<int>(right),
- static_cast<int>(bottom));
-}
-
-///////////////////////////////////////////////
-template <typename FakeComposerService>
-class DisplayTest : public ::testing::Test {
-protected:
- struct TestConfig {
- int32_t id;
- int32_t w;
- int32_t h;
- int32_t vsyncPeriod;
- int32_t group;
- };
-
- static int processDisplayEvents(int /*fd*/, int /*events*/, void* data) {
- auto self = static_cast<DisplayTest*>(data);
-
- ssize_t n;
- DisplayEventReceiver::Event buffer[1];
-
- while ((n = self->mReceiver->getEvents(buffer, 1)) > 0) {
- for (int i = 0; i < n; i++) {
- self->mReceivedDisplayEvents.push_back(buffer[i]);
- }
- }
- ALOGD_IF(n < 0, "Error reading events (%s)", strerror(-n));
- return 1;
- }
-
- Error getDisplayAttributeNoMock(Display display, Config config,
- V2_4::IComposerClient::Attribute attribute, int32_t* outValue) {
- mFakeComposerClient->setMockHal(nullptr);
- auto ret =
- mFakeComposerClient->getDisplayAttribute_2_4(display, config, attribute, outValue);
- mFakeComposerClient->setMockHal(mMockComposer.get());
- return ret;
- }
-
- void setExpectationsForConfigs(Display display, std::vector<TestConfig> testConfigs,
- Config activeConfig, V2_4::VsyncPeriodNanos defaultVsyncPeriod) {
- std::vector<Config> configIds;
- for (size_t i = 0; i < testConfigs.size(); i++) {
- configIds.push_back(testConfigs[i].id);
-
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].w), Return(Error::NONE)));
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::HEIGHT, _))
- .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].h), Return(Error::NONE)));
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::VSYNC_PERIOD,
- _))
- .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].vsyncPeriod),
- Return(Error::NONE)));
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::CONFIG_GROUP,
- _))
- .WillRepeatedly(
- DoAll(SetArgPointee<3>(testConfigs[i].group), Return(Error::NONE)));
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::DPI_X, _))
- .WillRepeatedly(Return(Error::UNSUPPORTED));
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::DPI_Y, _))
- .WillRepeatedly(Return(Error::UNSUPPORTED));
- }
-
- EXPECT_CALL(*mMockComposer, getDisplayConfigs(display, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(hidl_vec<Config>(configIds)),
- Return(V2_1::Error::NONE)));
-
- EXPECT_CALL(*mMockComposer, getActiveConfig(display, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(activeConfig), Return(V2_1::Error::NONE)));
-
- EXPECT_CALL(*mMockComposer, getDisplayVsyncPeriod(display, _))
- .WillRepeatedly(
- DoAll(SetArgPointee<1>(defaultVsyncPeriod), Return(V2_4::Error::NONE)));
- }
-
- void SetUp() override {
- mMockComposer = std::make_unique<MockComposerHal>();
- mFakeComposerClient = new FakeComposerClient();
- mFakeComposerClient->setMockHal(mMockComposer.get());
-
- auto client = sp<V2_4::hal::ComposerClient>::make(mFakeComposerClient);
- mFakeService = sp<FakeComposerService>::make(client);
- ASSERT_EQ(android::OK, mFakeService->registerAsService("mock"));
-
- android::hardware::ProcessState::self()->startThreadPool();
- android::ProcessState::self()->startThreadPool();
-
- setExpectationsForConfigs(PRIMARY_DISPLAY,
- {{
- .id = 1,
- .w = 1920,
- .h = 1024,
- .vsyncPeriod = 16'666'666,
- .group = 0,
- }},
- 1, 16'666'666);
-
- startSurfaceFlinger();
-
- // Fake composer wants to enable VSync injection
- mFakeComposerClient->onSurfaceFlingerStart();
-
- mComposerClient = sp<SurfaceComposerClient>::make();
- ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
- mReceiver.reset(
- new DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
- gui::ISurfaceComposer::EventRegistration::modeChanged));
- mLooper = sp<Looper>::make(false);
- mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
- }
-
- void TearDown() override {
- mLooper = nullptr;
- mReceiver = nullptr;
-
- mComposerClient->dispose();
- mComposerClient = nullptr;
-
- // Fake composer needs to release SurfaceComposerClient before the stop.
- mFakeComposerClient->onSurfaceFlingerStop();
- stopSurfaceFlinger();
-
- mFakeComposerClient->setMockHal(nullptr);
-
- mFakeService = nullptr;
- // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime
- // management.
- mMockComposer = nullptr;
- }
-
- void waitForDisplayTransaction(Display display) {
- // Both a refresh and a vsync event are needed to apply pending display
- // transactions.
- mFakeComposerClient->refreshDisplay(display);
- mFakeComposerClient->runVSyncAndWait();
-
- // Extra vsync and wait to avoid a 10% flake due to a race.
- mFakeComposerClient->runVSyncAndWait();
- }
-
- bool waitForHotplugEvent(Display displayId, bool connected) {
- return waitForHotplugEvent(physicalIdFromHwcDisplayId(displayId), connected);
- }
-
- bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
- int waitCount = 20;
- while (waitCount--) {
- while (!mReceivedDisplayEvents.empty()) {
- auto event = mReceivedDisplayEvents.front();
- mReceivedDisplayEvents.pop_front();
-
- ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
- "event hotplug: displayId %s, connected %d",
- to_string(event.header.displayId).c_str(), event.hotplug.connected);
-
- if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
- event.header.displayId == displayId && event.hotplug.connected == connected) {
- return true;
- }
- }
-
- mLooper->pollOnce(1);
- }
- return false;
- }
-
- bool waitForModeChangedEvent(Display display, int32_t modeId) {
- PhysicalDisplayId displayId = physicalIdFromHwcDisplayId(display);
- int waitCount = 20;
- while (waitCount--) {
- while (!mReceivedDisplayEvents.empty()) {
- auto event = mReceivedDisplayEvents.front();
- mReceivedDisplayEvents.pop_front();
-
- ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE,
- "event mode: displayId %s, modeId %d",
- to_string(event.header.displayId).c_str(), event.modeChange.modeId);
-
- if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE &&
- event.header.displayId == displayId && event.modeChange.modeId == modeId) {
- return true;
- }
- }
-
- mLooper->pollOnce(1);
- }
- return false;
- }
-
- void Test_HotplugOneConfig() {
- ALOGD("DisplayTest::Test_Hotplug_oneConfig");
-
- setExpectationsForConfigs(EXTERNAL_DISPLAY,
- {{.id = 1,
- .w = 200,
- .h = 400,
- .vsyncPeriod = 16'666'666,
- .group = 0}},
- 1, 16'666'666);
-
- mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
- V2_1::IComposerCallback::Connection::CONNECTED);
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
-
- {
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
- EXPECT_FALSE(display == nullptr);
-
- ui::DisplayMode mode;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- const ui::Size& resolution = mode.resolution;
- EXPECT_EQ(ui::Size(200, 400), resolution);
- EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
-
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
- V2_1::IComposerCallback::Connection::DISCONNECTED);
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- mFakeComposerClient->clearFrames();
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
-
- {
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
- EXPECT_TRUE(display == nullptr);
-
- ui::DisplayMode mode;
- EXPECT_NE(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- }
- }
-
- void Test_HotplugTwoSeparateConfigs() {
- ALOGD("DisplayTest::Test_HotplugTwoSeparateConfigs");
-
- setExpectationsForConfigs(EXTERNAL_DISPLAY,
- {{.id = 1,
- .w = 200,
- .h = 400,
- .vsyncPeriod = 16'666'666,
- .group = 0},
- {.id = 2,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 11'111'111,
- .group = 1}},
- 1, 16'666'666);
-
- mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
- V2_1::IComposerCallback::Connection::CONNECTED);
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
-
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
- EXPECT_FALSE(display == nullptr);
-
- ui::DisplayMode mode;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(200, 400), mode.resolution);
- EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
-
- mFakeComposerClient->clearFrames();
- {
- const ui::Size& resolution = mode.resolution;
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- ui::DynamicDisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
- const auto& modes = info.supportedDisplayModes;
- EXPECT_EQ(modes.size(), 2);
-
- // change active mode
-
- if (mIs2_4Client) {
- EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 2, _, _))
- .WillOnce(Return(V2_4::Error::NONE));
- } else {
- EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 2))
- .WillOnce(Return(V2_1::Error::NONE));
- }
-
- for (int i = 0; i < modes.size(); i++) {
- const auto& mode = modes[i];
- if (mode.resolution.getWidth() == 800) {
- EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
- mode.refreshRate,
- mode.refreshRate,
- mode.refreshRate,
- mode.refreshRate));
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
- break;
- }
- }
-
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
- EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
-
- mFakeComposerClient->clearFrames();
- {
- const ui::Size& resolution = mode.resolution;
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
- V2_1::IComposerCallback::Connection::DISCONNECTED);
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- mFakeComposerClient->clearFrames();
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
- }
-
- void Test_HotplugTwoConfigsSameGroup() {
- ALOGD("DisplayTest::Test_HotplugTwoConfigsSameGroup");
-
- setExpectationsForConfigs(EXTERNAL_DISPLAY,
- {{.id = 2,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 16'666'666,
- .group = 31},
- {.id = 3,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 11'111'111,
- .group = 31}},
- 2, 16'666'666);
-
- mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
- V2_1::IComposerCallback::Connection::CONNECTED);
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
-
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
- EXPECT_FALSE(display == nullptr);
-
- ui::DisplayMode mode;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
- EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
-
- mFakeComposerClient->clearFrames();
- {
- const ui::Size& resolution = mode.resolution;
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- ui::DynamicDisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
- const auto& modes = info.supportedDisplayModes;
- EXPECT_EQ(modes.size(), 2);
-
- // change active mode
- if (mIs2_4Client) {
- EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 3, _, _))
- .WillOnce(Return(V2_4::Error::NONE));
- } else {
- EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 3))
- .WillOnce(Return(V2_1::Error::NONE));
- }
-
- for (int i = 0; i < modes.size(); i++) {
- const auto& mode = modes[i];
- if (mode.refreshRate == 1e9f / 11'111'111) {
- EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
- mode.refreshRate,
- mode.refreshRate,
- mode.refreshRate,
- mode.refreshRate));
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
- break;
- }
- }
-
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
- EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
-
- mFakeComposerClient->clearFrames();
- {
- const ui::Size& resolution = mode.resolution;
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
- V2_1::IComposerCallback::Connection::DISCONNECTED);
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- mFakeComposerClient->clearFrames();
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
- }
-
- void Test_HotplugThreeConfigsMixedGroups() {
- ALOGD("DisplayTest::Test_HotplugThreeConfigsMixedGroups");
-
- setExpectationsForConfigs(EXTERNAL_DISPLAY,
- {{.id = 2,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 16'666'666,
- .group = 0},
- {.id = 3,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 11'111'111,
- .group = 0},
- {.id = 4,
- .w = 1600,
- .h = 3200,
- .vsyncPeriod = 8'333'333,
- .group = 1},
- {.id = 5,
- .w = 1600,
- .h = 3200,
- .vsyncPeriod = 11'111'111,
- .group = 1}},
- 2, 16'666'666);
-
- mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
- V2_1::IComposerCallback::Connection::CONNECTED);
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
-
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
- EXPECT_FALSE(display == nullptr);
-
- ui::DisplayMode mode;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
- EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
-
- mFakeComposerClient->clearFrames();
- {
- const ui::Size& resolution = mode.resolution;
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- ui::DynamicDisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
- const auto& modes = info.supportedDisplayModes;
- EXPECT_EQ(modes.size(), 4);
-
- // change active mode to 800x1600@90Hz
- if (mIs2_4Client) {
- EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 3, _, _))
- .WillOnce(Return(V2_4::Error::NONE));
- } else {
- EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 3))
- .WillOnce(Return(V2_1::Error::NONE));
- }
-
- for (size_t i = 0; i < modes.size(); i++) {
- const auto& mode = modes[i];
- if (mode.resolution.getWidth() == 800 && mode.refreshRate == 1e9f / 11'111'111) {
- EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
- modes[i].refreshRate,
- modes[i].refreshRate,
- modes[i].refreshRate,
- modes[i].refreshRate));
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
- break;
- }
- }
-
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
- EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
-
- mFakeComposerClient->clearFrames();
- {
- const ui::Size& resolution = mode.resolution;
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- // change active mode to 1600x3200@120Hz
- if (mIs2_4Client) {
- EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 4, _, _))
- .WillOnce(Return(V2_4::Error::NONE));
- } else {
- EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 4))
- .WillOnce(Return(V2_1::Error::NONE));
- }
-
- for (int i = 0; i < modes.size(); i++) {
- const auto& mode = modes[i];
- if (mode.refreshRate == 1e9f / 8'333'333) {
- EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
- mode.refreshRate,
- mode.refreshRate,
- mode.refreshRate,
- mode.refreshRate));
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
- break;
- }
- }
-
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(1600, 3200), mode.resolution);
- EXPECT_EQ(1e9f / 8'333'333, mode.refreshRate);
-
- mFakeComposerClient->clearFrames();
- {
- const ui::Size& resolution = mode.resolution;
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- // change active mode to 1600x3200@90Hz
- if (mIs2_4Client) {
- EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 5, _, _))
- .WillOnce(Return(V2_4::Error::NONE));
- } else {
- EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 5))
- .WillOnce(Return(V2_1::Error::NONE));
- }
-
- for (int i = 0; i < modes.size(); i++) {
- const auto& mode = modes[i];
- if (mode.resolution.getWidth() == 1600 && mode.refreshRate == 1e9f / 11'111'111) {
- EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
- mode.refreshRate,
- mode.refreshRate,
- mode.refreshRate,
- mode.refreshRate));
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
- break;
- }
- }
-
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(1600, 3200), mode.resolution);
- EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
-
- mFakeComposerClient->clearFrames();
- {
- const ui::Size& resolution = mode.resolution;
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"),
- resolution.getWidth(), resolution.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 0);
- EXPECT_TRUE(surfaceControl != nullptr);
- EXPECT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
-
- {
- TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
- }
- }
-
- mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
- V2_1::IComposerCallback::Connection::DISCONNECTED);
- waitForDisplayTransaction(EXTERNAL_DISPLAY);
- mFakeComposerClient->clearFrames();
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
- }
-
- void Test_HotplugPrimaryDisplay() {
- ALOGD("DisplayTest::HotplugPrimaryDisplay");
-
- mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
- V2_1::IComposerCallback::Connection::DISCONNECTED);
-
- waitForDisplayTransaction(PRIMARY_DISPLAY);
-
- EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
- {
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kPrimaryDisplayId);
- EXPECT_TRUE(display == nullptr);
-
- ui::DisplayMode mode;
- auto result = SurfaceComposerClient::getActiveDisplayMode(display, &mode);
- EXPECT_NE(NO_ERROR, result);
- }
-
- mFakeComposerClient->clearFrames();
-
- setExpectationsForConfigs(PRIMARY_DISPLAY,
- {{.id = 1,
- .w = 400,
- .h = 200,
- .vsyncPeriod = 16'666'666,
- .group = 0}},
- 1, 16'666'666);
-
- mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
- V2_1::IComposerCallback::Connection::CONNECTED);
-
- waitForDisplayTransaction(PRIMARY_DISPLAY);
-
- EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
-
- {
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kPrimaryDisplayId);
- EXPECT_FALSE(display == nullptr);
-
- ui::DisplayMode mode;
- auto result = SurfaceComposerClient::getActiveDisplayMode(display, &mode);
- EXPECT_EQ(NO_ERROR, result);
- ASSERT_EQ(ui::Size(400, 200), mode.resolution);
- EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
- }
- }
-
- void Test_SubsequentHotplugConnectUpdatesDisplay(Display hwcDisplayId) {
- ALOGD("DisplayTest::Test_SubsequentHotplugConnectUpdatesDisplay");
-
- // Send a hotplug connected event to set up the initial display modes.
- // The primary display is already connected so this will update it.
- // If we're running the test of an external display this will create it.
- setExpectationsForConfigs(hwcDisplayId,
- {{.id = 1,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 11'111'111,
- .group = 1}},
- /* activeConfig */ 1, 11'111'111);
-
- mFakeComposerClient->hotplugDisplay(hwcDisplayId,
- V2_1::IComposerCallback::Connection::CONNECTED);
- waitForDisplayTransaction(hwcDisplayId);
- EXPECT_TRUE(waitForHotplugEvent(hwcDisplayId, true));
-
- const auto displayId = physicalIdFromHwcDisplayId(hwcDisplayId);
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(displayId);
- EXPECT_FALSE(display == nullptr);
-
- // Verify that the active mode and the supported moded are updated
- {
- ui::DisplayMode mode;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
- EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
-
- ui::DynamicDisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
- const auto& modes = info.supportedDisplayModes;
- EXPECT_EQ(modes.size(), 1);
- }
-
- // Send another hotplug connected event
- setExpectationsForConfigs(hwcDisplayId,
- {
- {.id = 1,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 16'666'666,
- .group = 1},
- {.id = 2,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 11'111'111,
- .group = 1},
- {.id = 3,
- .w = 800,
- .h = 1600,
- .vsyncPeriod = 8'333'333,
- .group = 1},
- },
- /* activeConfig */ 1, 16'666'666);
-
- mFakeComposerClient->hotplugDisplay(hwcDisplayId,
- V2_1::IComposerCallback::Connection::CONNECTED);
- waitForDisplayTransaction(hwcDisplayId);
- EXPECT_TRUE(waitForHotplugEvent(hwcDisplayId, true));
-
- // Verify that the active mode and the supported moded are updated
- {
- ui::DisplayMode mode;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
- EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
- }
-
- ui::DynamicDisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
- const auto& modes = info.supportedDisplayModes;
- EXPECT_EQ(modes.size(), 3);
-
- EXPECT_EQ(ui::Size(800, 1600), modes[0].resolution);
- EXPECT_EQ(1e9f / 16'666'666, modes[0].refreshRate);
-
- EXPECT_EQ(ui::Size(800, 1600), modes[1].resolution);
- EXPECT_EQ(1e9f / 11'111'111, modes[1].refreshRate);
-
- EXPECT_EQ(ui::Size(800, 1600), modes[2].resolution);
- EXPECT_EQ(1e9f / 8'333'333, modes[2].refreshRate);
-
- // Verify that we are able to switch to any of the modes
- for (int i = modes.size() - 1; i >= 0; i--) {
- const auto hwcId = i + 1;
- // Set up HWC expectations for the mode change
- if (mIs2_4Client) {
- EXPECT_CALL(*mMockComposer,
- setActiveConfigWithConstraints(hwcDisplayId, hwcId, _, _))
- .WillOnce(Return(V2_4::Error::NONE));
- } else {
- EXPECT_CALL(*mMockComposer, setActiveConfig(hwcDisplayId, hwcId))
- .WillOnce(Return(V2_1::Error::NONE));
- }
-
- EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
- modes[i].refreshRate,
- modes[i].refreshRate,
- modes[i].refreshRate,
- modes[i].refreshRate));
- // We need to refresh twice - once to apply the pending mode change request,
- // and once to process the change.
- waitForDisplayTransaction(hwcDisplayId);
- waitForDisplayTransaction(hwcDisplayId);
- EXPECT_TRUE(waitForModeChangedEvent(hwcDisplayId, i))
- << "Failure while switching to mode " << i;
-
- ui::DisplayMode mode;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
- EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
- EXPECT_EQ(modes[i].refreshRate, mode.refreshRate);
- }
- }
-
- sp<V2_1::IComposer> mFakeService;
- sp<SurfaceComposerClient> mComposerClient;
-
- std::unique_ptr<MockComposerHal> mMockComposer;
- FakeComposerClient* mFakeComposerClient;
-
- std::unique_ptr<DisplayEventReceiver> mReceiver;
- sp<Looper> mLooper;
- std::deque<DisplayEventReceiver::Event> mReceivedDisplayEvents;
-
- static constexpr bool mIs2_4Client =
- std::is_same<FakeComposerService, FakeComposerService_2_4>::value;
-};
-
-using DisplayTest_2_1 = DisplayTest<FakeComposerService_2_1>;
-
-// Tests that VSYNC injection can be safely toggled while invalidating.
-TEST_F(DisplayTest_2_1, VsyncInjection) {
- const auto flinger = ComposerServiceAIDL::getComposerService();
- bool enable = true;
-
- for (int i = 0; i < 100; i++) {
- flinger->enableVSyncInjections(enable);
- enable = !enable;
-
- constexpr uint32_t kForceInvalidate = 1004;
- android::Parcel data, reply;
- data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
- EXPECT_EQ(NO_ERROR,
- android::IInterface::asBinder(flinger)->transact(kForceInvalidate, data, &reply));
-
- std::this_thread::sleep_for(5ms);
- }
-}
-
-TEST_F(DisplayTest_2_1, HotplugOneConfig) {
- Test_HotplugOneConfig();
-}
-
-TEST_F(DisplayTest_2_1, HotplugTwoSeparateConfigs) {
- Test_HotplugTwoSeparateConfigs();
-}
-
-TEST_F(DisplayTest_2_1, HotplugTwoConfigsSameGroup) {
- Test_HotplugTwoConfigsSameGroup();
-}
-
-TEST_F(DisplayTest_2_1, HotplugThreeConfigsMixedGroups) {
- Test_HotplugThreeConfigsMixedGroups();
-}
-
-TEST_F(DisplayTest_2_1, HotplugPrimaryOneConfig) {
- Test_HotplugPrimaryDisplay();
-}
-
-TEST_F(DisplayTest_2_1, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
- Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
-}
-
-TEST_F(DisplayTest_2_1, SubsequentHotplugConnectUpdatesExternalDisplay) {
- Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
-}
-
-using DisplayTest_2_2 = DisplayTest<FakeComposerService_2_2>;
-
-TEST_F(DisplayTest_2_2, HotplugOneConfig) {
- Test_HotplugOneConfig();
-}
-
-TEST_F(DisplayTest_2_2, HotplugTwoSeparateConfigs) {
- Test_HotplugTwoSeparateConfigs();
-}
-
-TEST_F(DisplayTest_2_2, HotplugTwoConfigsSameGroup) {
- Test_HotplugTwoConfigsSameGroup();
-}
-
-TEST_F(DisplayTest_2_2, HotplugThreeConfigsMixedGroups) {
- Test_HotplugThreeConfigsMixedGroups();
-}
-
-TEST_F(DisplayTest_2_2, HotplugPrimaryOneConfig) {
- Test_HotplugPrimaryDisplay();
-}
-
-TEST_F(DisplayTest_2_2, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
- Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
-}
-
-TEST_F(DisplayTest_2_2, SubsequentHotplugConnectUpdatesExternalDisplay) {
- Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
-}
-
-using DisplayTest_2_3 = DisplayTest<FakeComposerService_2_3>;
-
-TEST_F(DisplayTest_2_3, HotplugOneConfig) {
- Test_HotplugOneConfig();
-}
-
-TEST_F(DisplayTest_2_3, HotplugTwoSeparateConfigs) {
- Test_HotplugTwoSeparateConfigs();
-}
-
-TEST_F(DisplayTest_2_3, HotplugTwoConfigsSameGroup) {
- Test_HotplugTwoConfigsSameGroup();
-}
-
-TEST_F(DisplayTest_2_3, HotplugThreeConfigsMixedGroups) {
- Test_HotplugThreeConfigsMixedGroups();
-}
-
-TEST_F(DisplayTest_2_3, HotplugPrimaryOneConfig) {
- Test_HotplugPrimaryDisplay();
-}
-
-TEST_F(DisplayTest_2_3, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
- Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
-}
-
-TEST_F(DisplayTest_2_3, SubsequentHotplugConnectUpdatesExternalDisplay) {
- Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
-}
-
-using DisplayTest_2_4 = DisplayTest<FakeComposerService_2_4>;
-
-TEST_F(DisplayTest_2_4, HotplugOneConfig) {
- Test_HotplugOneConfig();
-}
-
-TEST_F(DisplayTest_2_4, HotplugTwoSeparateConfigs) {
- Test_HotplugTwoSeparateConfigs();
-}
-
-TEST_F(DisplayTest_2_4, HotplugTwoConfigsSameGroup) {
- Test_HotplugTwoConfigsSameGroup();
-}
-
-TEST_F(DisplayTest_2_4, HotplugThreeConfigsMixedGroups) {
- Test_HotplugThreeConfigsMixedGroups();
-}
-
-TEST_F(DisplayTest_2_4, HotplugPrimaryOneConfig) {
- Test_HotplugPrimaryDisplay();
-}
-
-TEST_F(DisplayTest_2_4, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
- Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
-}
-
-TEST_F(DisplayTest_2_4, SubsequentHotplugConnectUpdatesExternalDisplay) {
- Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
-}
-
-////////////////////////////////////////////////
-
-template <typename FakeComposerService>
-class TransactionTest : public ::testing::Test {
-protected:
- // Layer array indexing constants.
- constexpr static int BG_LAYER = 0;
- constexpr static int FG_LAYER = 1;
-
- static void SetUpTestCase() {
- // TODO: See TODO comment at DisplayTest::SetUp for background on
- // the lifetime of the FakeComposerClient.
- sFakeComposer = new FakeComposerClient;
- auto client = sp<V2_4::hal::ComposerClient>::make(sFakeComposer);
- sp<V2_1::IComposer> fakeService = sp<FakeComposerService>::make(client);
- (void)fakeService->registerAsService("mock");
-
- android::hardware::ProcessState::self()->startThreadPool();
- android::ProcessState::self()->startThreadPool();
-
- startSurfaceFlinger();
-
- // Fake composer wants to enable VSync injection
- sFakeComposer->onSurfaceFlingerStart();
- }
-
- static void TearDownTestCase() {
- // Fake composer needs to release SurfaceComposerClient before the stop.
- sFakeComposer->onSurfaceFlingerStop();
- stopSurfaceFlinger();
- // TODO: This is deleted when the ComposerClient calls
- // removeClient. Devise better lifetime control.
- sFakeComposer = nullptr;
- }
-
- void SetUp() override {
- ALOGI("TransactionTest::SetUp");
- mComposerClient = sp<SurfaceComposerClient>::make();
- ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
- ALOGI("TransactionTest::SetUp - display");
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kPrimaryDisplayId);
- ASSERT_FALSE(display == nullptr);
-
- ui::DisplayMode mode;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
-
- const ui::Size& resolution = mode.resolution;
- mDisplayWidth = resolution.getWidth();
- mDisplayHeight = resolution.getHeight();
-
- // Background surface
- mBGSurfaceControl =
- mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth,
- mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mBGSurfaceControl != nullptr);
- ASSERT_TRUE(mBGSurfaceControl->isValid());
- fillSurfaceRGBA8(mBGSurfaceControl, BLUE);
-
- // Foreground surface
- mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
- PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mFGSurfaceControl != nullptr);
- ASSERT_TRUE(mFGSurfaceControl->isValid());
-
- fillSurfaceRGBA8(mFGSurfaceControl, RED);
-
- Transaction t;
- t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
-
- t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
- t.show(mBGSurfaceControl);
-
- t.setLayer(mFGSurfaceControl, INT32_MAX - 1);
- t.setPosition(mFGSurfaceControl, 64, 64);
- t.show(mFGSurfaceControl);
-
- // Synchronous transaction will stop this thread, so we set up a
- // delayed, off-thread vsync request before closing the
- // transaction. In the test code this is usually done with
- // TransactionScope. Leaving here in the 'vanilla' form for
- // reference.
- ASSERT_EQ(0, sFakeComposer->getFrameCount());
- sFakeComposer->runVSyncAfter(1ms);
- t.apply();
- sFakeComposer->waitUntilFrame(1);
-
- // Reference data. This is what the HWC should see.
- static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing");
- mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight));
- mBaseFrame[BG_LAYER].mSwapCount = 1;
- mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
- mBaseFrame[FG_LAYER].mSwapCount = 1;
-
- auto frame = sFakeComposer->getFrameRects(0);
- ASSERT_TRUE(framesAreSame(mBaseFrame, frame));
- }
-
- void TearDown() override {
- ALOGD("TransactionTest::TearDown");
-
- mComposerClient->dispose();
- mBGSurfaceControl = 0;
- mFGSurfaceControl = 0;
- mComposerClient = 0;
-
- sFakeComposer->runVSyncAndWait();
- mBaseFrame.clear();
- sFakeComposer->clearFrames();
- ASSERT_EQ(0, sFakeComposer->getFrameCount());
-
- sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
- std::vector<gui::LayerDebugInfo> layers;
- binder::Status status = sf->getLayerDebugInfo(&layers);
- status_t result = gui::aidl_utils::statusTFromBinderStatus(status);
- if (result != NO_ERROR) {
- ALOGE("Failed to get layers %s %d", strerror(-result), result);
- } else {
- // If this fails, the test being torn down leaked layers.
- EXPECT_EQ(0u, layers.size());
- if (layers.size() > 0) {
- for (auto layer = layers.begin(); layer != layers.end(); ++layer) {
- std::cout << to_string(*layer).c_str();
- }
- // To ensure the next test has clean slate, will run the class
- // tear down and setup here.
- TearDownTestCase();
- SetUpTestCase();
- }
- }
- ALOGD("TransactionTest::TearDown - complete");
- }
-
- void Test_LayerMove() {
- ALOGD("TransactionTest::LayerMove");
-
- // The scope opens and closes a global transaction and, at the
- // same time, makes sure the SurfaceFlinger progresses one frame
- // after the transaction closes. The results of the transaction
- // should be available in the latest frame stored by the fake
- // composer.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 128, 128);
- // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
- // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
- //
- // sFakeComposer->runVSyncAndWait();
- }
-
- fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
- sFakeComposer->runVSyncAndWait();
-
- ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and
- // there's no extra frames.
-
- // NOTE: Frame 0 is produced in the SetUp.
- auto frame1Ref = mBaseFrame;
- frame1Ref[FG_LAYER].mDisplayFrame =
- hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves.
- EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
-
- auto frame2Ref = frame1Ref;
- frame2Ref[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
- }
-
- void Test_LayerCrop() {
- // TODO: Add scaling to confirm that crop happens in buffer space?
- {
- TransactionScope ts(*sFakeComposer);
- Rect cropRect(16, 16, 32, 32);
- ts.setCrop(mFGSurfaceControl, cropRect);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f};
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerSetLayer() {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- // The layers will switch order, but both are rendered because the background layer is
- // transparent (RGBA8888).
- std::vector<RenderState> referenceFrame(2);
- referenceFrame[0] = mBaseFrame[FG_LAYER];
- referenceFrame[1] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerSetLayerOpaque() {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
- ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque,
- layer_state_t::eLayerOpaque);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- // The former foreground layer is now covered with opaque layer - it should have disappeared
- std::vector<RenderState> referenceFrame(1);
- referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
- }
-
- void Test_SetLayerStack() {
- ALOGD("TransactionTest::SetLayerStack");
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayerStack(mFGSurfaceControl, ui::LayerStack{1});
- }
-
- // Foreground layer should have disappeared.
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- std::vector<RenderState> refFrame(1);
- refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerShowHide() {
- ALOGD("TransactionTest::LayerShowHide");
- {
- TransactionScope ts(*sFakeComposer);
- ts.hide(mFGSurfaceControl);
- }
-
- // Foreground layer should have disappeared.
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- std::vector<RenderState> refFrame(1);
- refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mFGSurfaceControl);
- }
-
- // Foreground layer should be back
- ASSERT_EQ(3, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerSetAlpha() {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 0.75f);
- }
-
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerSetFlags() {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden,
- layer_state_t::eLayerHidden);
- }
-
- // Foreground layer should have disappeared.
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- std::vector<RenderState> refFrame(1);
- refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerSetMatrix() {
- struct matrixTestData {
- float matrix[4];
- hwc_transform_t expectedTransform;
- hwc_rect_t expectedDisplayFrame;
- };
-
- // The matrix operates on the display frame and is applied before
- // the position is added. So, the foreground layer rect is (0, 0,
- // 64, 64) is first transformed, potentially yielding negative
- // coordinates and then the position (64, 64) is added yielding
- // the final on-screen rectangles given.
-
- const matrixTestData MATRIX_TESTS[7] = // clang-format off
- {{{-1.f, 0.f, 0.f, 1.f}, HWC_TRANSFORM_FLIP_H, {0, 64, 64, 128}},
- {{1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_FLIP_V, {64, 0, 128, 64}},
- {{0.f, 1.f, -1.f, 0.f}, HWC_TRANSFORM_ROT_90, {0, 64, 64, 128}},
- {{-1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_ROT_180, {0, 0, 64, 64}},
- {{0.f, -1.f, 1.f, 0.f}, HWC_TRANSFORM_ROT_270, {64, 0, 128, 64}},
- {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}},
- {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}};
- // clang-format on
- constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
-
- for (int i = 0; i < TEST_COUNT; i++) {
- // TODO: How to leverage the HWC2 stringifiers?
- const matrixTestData& xform = MATRIX_TESTS[i];
- SCOPED_TRACE(i);
- {
- TransactionScope ts(*sFakeComposer);
- ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1], xform.matrix[2],
- xform.matrix[3]);
- }
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mTransform = xform.expectedTransform;
- referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame;
-
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
- }
- }
-
- void Test_SetRelativeLayer() {
- constexpr int RELATIVE_LAYER = 2;
- auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64,
- 64, PIXEL_FORMAT_RGBA_8888, 0);
- fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED);
-
- // Now we stack the surface above the foreground surface and make sure it is visible.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(relativeSurfaceControl, 64, 64);
- ts.show(relativeSurfaceControl);
- ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl, 1);
- }
- auto referenceFrame = mBaseFrame;
- // NOTE: All three layers will be visible as the surfaces are
- // transparent because of the RGBA format.
- referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
- referenceFrame[RELATIVE_LAYER].mSwapCount = 1;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // A call to setLayer will override a call to setRelativeLayer
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayer(relativeSurfaceControl, 0);
- }
-
- // Previous top layer will now appear at the bottom.
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]);
- EXPECT_EQ(3, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
- }
-
- sp<SurfaceComposerClient> mComposerClient;
- sp<SurfaceControl> mBGSurfaceControl;
- sp<SurfaceControl> mFGSurfaceControl;
- std::vector<RenderState> mBaseFrame;
- uint32_t mDisplayWidth;
- uint32_t mDisplayHeight;
-
- static inline FakeComposerClient* sFakeComposer;
-};
-
-using TransactionTest_2_1 = TransactionTest<FakeComposerService_2_1>;
-
-TEST_F(TransactionTest_2_1, DISABLED_LayerMove) {
- Test_LayerMove();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_LayerCrop) {
- Test_LayerCrop();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_LayerSetLayer) {
- Test_LayerSetLayer();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_LayerSetLayerOpaque) {
- Test_LayerSetLayerOpaque();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_SetLayerStack) {
- Test_SetLayerStack();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_LayerShowHide) {
- Test_LayerShowHide();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_LayerSetAlpha) {
- Test_LayerSetAlpha();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_LayerSetFlags) {
- Test_LayerSetFlags();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_LayerSetMatrix) {
- Test_LayerSetMatrix();
-}
-
-TEST_F(TransactionTest_2_1, DISABLED_SetRelativeLayer) {
- Test_SetRelativeLayer();
-}
-
-template <typename FakeComposerService>
-class ChildLayerTest : public TransactionTest<FakeComposerService> {
- using Base = TransactionTest<FakeComposerService>;
-
-protected:
- constexpr static int CHILD_LAYER = 2;
-
- void SetUp() override {
- Base::SetUp();
- mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0,
- Base::mFGSurfaceControl->getHandle());
- fillSurfaceRGBA8(mChild, LIGHT_GRAY);
-
- Base::sFakeComposer->runVSyncAndWait();
- Base::mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
- Base::mBaseFrame[CHILD_LAYER].mSwapCount = 1;
- ASSERT_EQ(2, Base::sFakeComposer->getFrameCount());
- ASSERT_TRUE(framesAreSame(Base::mBaseFrame, Base::sFakeComposer->getLatestFrame()));
- }
-
- void TearDown() override {
- mChild = 0;
- Base::TearDown();
- }
-
- void Test_Positioning() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 10, 10);
- // Move to the same position as in the original setup.
- ts.setPosition(Base::mFGSurfaceControl, 64, 64);
- }
-
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame =
- hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- }
-
- auto referenceFrame2 = Base::mBaseFrame;
- referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64};
- referenceFrame2[CHILD_LAYER].mDisplayFrame =
- hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10};
- EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
- }
-
- void Test_Cropping() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 5, 5));
- }
- // NOTE: The foreground surface would be occluded by the child
- // now, but is included in the stack because the child is
- // transparent.
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
- referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
- referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
- }
-
- void Test_Constraints() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.show(mChild);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- ts.setPosition(mChild, 63, 63);
- }
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64};
- referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f};
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
- }
-
- void Test_Scaling() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- }
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setMatrix(Base::mFGSurfaceControl, 2.0, 0, 0, 2.0);
- }
-
- auto referenceFrame2 = Base::mBaseFrame;
- referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
- referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
- EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerAlpha() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- ts.setAlpha(mChild, 0.5);
- }
-
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setAlpha(Base::mFGSurfaceControl, 0.5);
- }
-
- auto referenceFrame2 = referenceFrame;
- referenceFrame2[Base::FG_LAYER].mPlaneAlpha = 0.5f;
- referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
- EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
- }
-
- sp<SurfaceControl> mChild;
-};
-
-using ChildLayerTest_2_1 = ChildLayerTest<FakeComposerService_2_1>;
-
-TEST_F(ChildLayerTest_2_1, DISABLED_Positioning) {
- Test_Positioning();
-}
-
-TEST_F(ChildLayerTest_2_1, DISABLED_Cropping) {
- Test_Cropping();
-}
-
-TEST_F(ChildLayerTest_2_1, DISABLED_Constraints) {
- Test_Constraints();
-}
-
-TEST_F(ChildLayerTest_2_1, DISABLED_Scaling) {
- Test_Scaling();
-}
-
-TEST_F(ChildLayerTest_2_1, DISABLED_LayerAlpha) {
- Test_LayerAlpha();
-}
-
-template <typename FakeComposerService>
-class ChildColorLayerTest : public ChildLayerTest<FakeComposerService> {
- using Base = ChildLayerTest<FakeComposerService>;
-
-protected:
- void SetUp() override {
- Base::SetUp();
- Base::mChild =
- Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceEffect,
- Base::mFGSurfaceControl->getHandle());
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setColor(Base::mChild,
- {LIGHT_GRAY.r / 255.0f, LIGHT_GRAY.g / 255.0f, LIGHT_GRAY.b / 255.0f});
- ts.setCrop(Base::mChild, Rect(0, 0, 10, 10));
- }
-
- Base::sFakeComposer->runVSyncAndWait();
- Base::mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
- Base::mBaseFrame[Base::CHILD_LAYER].mSourceCrop = hwc_frect_t{0.0f, 0.0f, 0.0f, 0.0f};
- Base::mBaseFrame[Base::CHILD_LAYER].mSwapCount = 0;
- ASSERT_EQ(2, Base::sFakeComposer->getFrameCount());
- ASSERT_TRUE(framesAreSame(Base::mBaseFrame, Base::sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerAlpha() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.show(Base::mChild);
- ts.setPosition(Base::mChild, 0, 0);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- ts.setAlpha(Base::mChild, 0.5);
- }
-
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[Base::CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- referenceFrame[Base::CHILD_LAYER].mPlaneAlpha = 0.5f;
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setAlpha(Base::mFGSurfaceControl, 0.5);
- }
-
- auto referenceFrame2 = referenceFrame;
- referenceFrame2[Base::FG_LAYER].mPlaneAlpha = 0.5f;
- referenceFrame2[Base::CHILD_LAYER].mPlaneAlpha = 0.25f;
- EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
- }
-
- void Test_LayerZeroAlpha() {
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.show(Base::mChild);
- ts.setPosition(Base::mChild, 0, 0);
- ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- ts.setAlpha(Base::mChild, 0.5);
- }
-
- auto referenceFrame = Base::mBaseFrame;
- referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[Base::CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- referenceFrame[Base::CHILD_LAYER].mPlaneAlpha = 0.5f;
- EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*Base::sFakeComposer);
- ts.setAlpha(Base::mFGSurfaceControl, 0.0f);
- }
-
- std::vector<RenderState> refFrame(1);
- refFrame[Base::BG_LAYER] = Base::mBaseFrame[Base::BG_LAYER];
-
- EXPECT_TRUE(framesAreSame(refFrame, Base::sFakeComposer->getLatestFrame()));
- }
-};
-
-using ChildColorLayerTest_2_1 = ChildColorLayerTest<FakeComposerService_2_1>;
-
-TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerAlpha) {
- Test_LayerAlpha();
-}
-
-TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerZeroAlpha) {
- Test_LayerZeroAlpha();
-}
-} // namespace
-
-int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
-
- auto* fakeEnvironment = new sftest::FakeHwcEnvironment;
- ::testing::AddGlobalTestEnvironment(fakeEnvironment);
- ::testing::InitGoogleMock(&argc, argv);
- return RUN_ALL_TESTS();
-}
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index dec14d0..d2b5813 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -34,7 +34,6 @@
"mock/MockFrameTimeline.cpp",
"mock/MockFrameTracer.cpp",
"mock/MockNativeWindowSurface.cpp",
- "mock/MockSurfaceInterceptor.cpp",
"mock/MockTimeStats.cpp",
"mock/MockVsyncController.cpp",
"mock/MockVSyncTracker.cpp",
@@ -109,6 +108,7 @@
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
"SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
+ "SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp",
"SchedulerTest.cpp",
"SetFrameRateTest.cpp",
"RefreshRateConfigsTest.cpp",
@@ -167,7 +167,6 @@
"libtimestats_atoms_proto",
"libtimestats_proto",
"libtonemap",
- "libtrace_proto",
"perfetto_trace_protos",
],
shared_libs: [
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 31262b3..e0b508a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -36,8 +36,7 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- // Default to no wide color display support configured
- mFlinger.mutableHasWideColorDisplay() = false;
+ mFlinger.mutableSupportsWideColor() = false;
mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
mFlinger.setCreateBufferQueueFunction([](auto, auto, auto) {
@@ -51,7 +50,6 @@
injectMockScheduler();
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
- mFlinger.mutableInterceptor() = mSurfaceInterceptor;
injectMockComposer(0);
}
@@ -122,51 +120,6 @@
});
}
-sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay(
- std::function<void(FakeDisplayDeviceInjector&)> injectExtra) {
- constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(255u);
- constexpr int DEFAULT_DISPLAY_WIDTH = 1080;
- constexpr int DEFAULT_DISPLAY_HEIGHT = 1920;
- constexpr HWDisplayId DEFAULT_DISPLAY_HWC_DISPLAY_ID = 0;
-
- // The DisplayDevice is required to have a framebuffer (behind the
- // ANativeWindow interface) which uses the actual hardware display
- // size.
- EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
- EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
- EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT));
- EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT));
- EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
- EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber());
-
- auto compositionDisplay =
- compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
- compositionengine::DisplayCreationArgsBuilder()
- .setId(DEFAULT_DISPLAY_ID)
- .setPixels({DEFAULT_DISPLAY_WIDTH,
- DEFAULT_DISPLAY_HEIGHT})
- .setPowerAdvisor(&mPowerAdvisor)
- .build());
-
- constexpr bool kIsPrimary = true;
- auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
- ui::DisplayConnectionType::Internal,
- DEFAULT_DISPLAY_HWC_DISPLAY_ID, kIsPrimary);
-
- injector.setNativeWindow(mNativeWindow);
- if (injectExtra) {
- injectExtra(injector);
- }
-
- auto displayDevice = injector.inject();
-
- Mock::VerifyAndClear(mNativeWindow.get());
-
- return displayDevice;
-}
-
bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) const {
const auto& map = mFlinger.hwcPhysicalDisplayIdMap();
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 885d6cd..19c7d5c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -42,6 +42,7 @@
#include <renderengine/mock/RenderEngine.h>
#include <ui/DebugUtils.h>
+#include "FakeDisplayInjector.h"
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -49,7 +50,6 @@
#include "mock/DisplayHardware/MockPowerAdvisor.h"
#include "mock/MockEventThread.h"
#include "mock/MockNativeWindowSurface.h"
-#include "mock/MockSurfaceInterceptor.h"
#include "mock/MockVsyncController.h"
#include "mock/system/window/MockNativeWindow.h"
@@ -89,8 +89,11 @@
void injectMockComposer(int virtualDisplayCount);
void injectFakeBufferQueueFactory();
void injectFakeNativeWindowSurfaceFactory();
+
sp<DisplayDevice> injectDefaultInternalDisplay(
- std::function<void(TestableSurfaceFlinger::FakeDisplayDeviceInjector&)>);
+ std::function<void(TestableSurfaceFlinger::FakeDisplayDeviceInjector&)> injectExtra) {
+ return mFakeDisplayInjector.injectInternalDisplay(injectExtra);
+ }
// --------------------------------------------------------------------
// Postcondition helpers
@@ -115,12 +118,13 @@
sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make();
Hwc2::mock::PowerAdvisor mPowerAdvisor;
+ FakeDisplayInjector mFakeDisplayInjector{mFlinger, mPowerAdvisor, mNativeWindow};
+
// These mocks are created by the test, but are destroyed by SurfaceFlinger
// by virtue of being stored into a std::unique_ptr. However we still need
// to keep a reference to them for use in setting up call expectations.
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
Hwc2::mock::Composer* mComposer = nullptr;
- sp<mock::SurfaceInterceptor> mSurfaceInterceptor = sp<mock::SurfaceInterceptor>::make();
mock::VsyncController* mVsyncController = new mock::VsyncController;
mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
@@ -679,12 +683,10 @@
static constexpr bool WIDE_COLOR_SUPPORTED = false;
static void injectConfigChange(DisplayTransactionTest* test) {
- test->mFlinger.mutableHasWideColorDisplay() = true;
+ test->mFlinger.mutableSupportsWideColor() = true;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>()), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
}
};
@@ -696,12 +698,11 @@
static constexpr bool WIDE_COLOR_SUPPORTED = false;
static void injectConfigChange(DisplayTransactionTest* test) {
- test->mFlinger.mutableHasWideColorDisplay() = false;
+ test->mFlinger.mutableSupportsWideColor() = false;
test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getColorModes(_, _)).Times(0);
EXPECT_CALL(*test->mComposer, getRenderIntents(_, _, _)).Times(0);
EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
}
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 978afc5..a5beaba 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -93,7 +93,6 @@
void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration,
std::chrono::nanoseconds expectedReadyDuration);
VSyncSource::Callback* expectVSyncSetCallbackCallReceived();
- void expectInterceptCallReceived(nsecs_t expectedTimestamp);
void expectVsyncEventReceivedByConnection(const char* name,
ConnectionEventRecorder& connectionEventRecorder,
nsecs_t expectedTimestamp, unsigned expectedCount);
@@ -114,7 +113,6 @@
AsyncCallRecorder<void (*)(std::chrono::nanoseconds, std::chrono::nanoseconds)>
mVSyncSetDurationCallRecorder;
AsyncCallRecorder<void (*)()> mResyncCallRecorder;
- AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t, uid_t)> mThrottleVsyncCallRecorder;
ConnectionEventRecorder mConnectionEventCallRecorder{0};
ConnectionEventRecorder mThrottledConnectionEventCallRecorder{0};
@@ -181,7 +179,6 @@
mTokenManager = std::make_unique<frametimeline::impl::TokenManager>();
mThread = std::make_unique<impl::EventThread>(std::move(source), mTokenManager.get(),
- mInterceptVSyncCallRecorder.getInvocable(),
throttleVsync, getVsyncPeriod);
// EventThread should register itself as VSyncSource callback.
@@ -219,12 +216,6 @@
return callbackSet.has_value() ? std::get<0>(callbackSet.value()) : nullptr;
}
-void EventThreadTest::expectInterceptCallReceived(nsecs_t expectedTimestamp) {
- auto args = mInterceptVSyncCallRecorder.waitForCall();
- ASSERT_TRUE(args.has_value());
- EXPECT_EQ(expectedTimestamp, std::get<0>(args.value()));
-}
-
void EventThreadTest::expectThrottleVsyncReceived(nsecs_t expectedTimestamp, uid_t uid) {
auto args = mThrottleVsyncCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
@@ -348,7 +339,6 @@
EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mVSyncSetDurationCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value());
- EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
}
@@ -374,17 +364,15 @@
expectVSyncSetEnabledCallReceived(true);
// Use the received callback to signal a first vsync event.
- // The interceptor should receive the event, as well as the connection.
+ // The throttler should receive the event, as well as the connection.
mCallback->onVSyncEvent(123, {456, 789});
- expectInterceptCallReceived(123);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
// Use the received callback to signal a second vsync event.
- // The interceptor should receive the event, but the connection should
+ // The throttler should receive the event, but the connection should
// not as it was only interested in the first.
mCallback->onVSyncEvent(456, {123, 0});
- expectInterceptCallReceived(456);
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -400,10 +388,9 @@
expectVSyncSetEnabledCallReceived(true);
// Use the received callback to signal a vsync event.
- // The interceptor should receive the event, as well as the connection.
+ // The throttler should receive the event, as well as the connection.
VSyncSource::VSyncData vsyncData = {456, 789};
mCallback->onVSyncEvent(123, vsyncData);
- expectInterceptCallReceived(123);
expectVsyncEventFrameTimelinesCorrect(123, vsyncData);
}
@@ -477,10 +464,9 @@
expectVSyncSetEnabledCallReceived(true);
// Send a vsync event. EventThread should then make a call to the
- // interceptor, and the second connection. The first connection should not
+ // the second connection. The first connection should not
// get the event.
mCallback->onVSyncEvent(123, {456, 0});
- expectInterceptCallReceived(123);
EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
1u);
@@ -493,21 +479,18 @@
expectVSyncSetEnabledCallReceived(true);
// Send a vsync event. EventThread should then make a call to the
- // interceptor, and the connection.
+ // throttler, and the connection.
mCallback->onVSyncEvent(123, {456, 789});
- expectInterceptCallReceived(123);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
// A second event should go to the same places.
mCallback->onVSyncEvent(456, {123, 0});
- expectInterceptCallReceived(456);
expectThrottleVsyncReceived(123, mConnectionUid);
expectVsyncEventReceivedByConnection(456, 2u);
// A third event should go to the same places.
mCallback->onVSyncEvent(789, {777, 111});
- expectInterceptCallReceived(789);
expectThrottleVsyncReceived(777, mConnectionUid);
expectVsyncEventReceivedByConnection(789, 3u);
}
@@ -518,27 +501,23 @@
// EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- // The first event will be seen by the interceptor, and not the connection.
+ // The first event will not be seen by the connection.
mCallback->onVSyncEvent(123, {456, 789});
- expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
- // The second event will be seen by the interceptor and the connection.
+ // The second event will be seen by the connection.
mCallback->onVSyncEvent(456, {123, 0});
- expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
- // The third event will be seen by the interceptor, and not the connection.
+ // The third event will not be seen by the connection.
mCallback->onVSyncEvent(789, {777, 744});
- expectInterceptCallReceived(789);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
- // The fourth event will be seen by the interceptor and the connection.
+ // The fourth event will be seen by the connection.
mCallback->onVSyncEvent(101112, {7847, 86});
- expectInterceptCallReceived(101112);
expectVsyncEventReceivedByConnection(101112, 4u);
}
@@ -551,9 +530,8 @@
// Destroy the only (strong) reference to the connection.
mConnection = nullptr;
- // The first event will be seen by the interceptor, and not the connection.
+ // The first event will not be seen by the connection.
mCallback->onVSyncEvent(123, {456, 789});
- expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// EventThread should disable vsync callbacks
@@ -568,16 +546,12 @@
// EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- // The first event will be seen by the interceptor, and by the connection,
- // which then returns an error.
+ // The first event will be seen by the connection, which then returns an error.
mCallback->onVSyncEvent(123, {456, 789});
- expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
- // A subsequent event will be seen by the interceptor and not by the
- // connection.
+ // A subsequent event will not be seen by the connection.
mCallback->onVSyncEvent(456, {123, 0});
- expectInterceptCallReceived(456);
EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
// EventThread should disable vsync callbacks with the second event
@@ -599,10 +573,8 @@
// EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- // The first event will be seen by the interceptor, and by the connection,
- // which then returns an error.
+ // The first event will be seen by the connection, which then returns an error.
mCallback->onVSyncEvent(123, {456, 789});
- expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
1u);
@@ -617,16 +589,13 @@
// EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- // The first event will be seen by the interceptor, and by the connection,
- // which then returns an non-fatal error.
+ // The first event will be seen by the connection, which then returns a non-fatal error.
mCallback->onVSyncEvent(123, {456, 789});
- expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
- // A subsequent event will be seen by the interceptor, and by the connection,
- // which still then returns an non-fatal error.
+ // A subsequent event will be seen by the connection, which still then returns a non-fatal
+ // error.
mCallback->onVSyncEvent(456, {123, 0});
- expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
// EventThread will not disable vsync callbacks as the errors are non-fatal.
@@ -748,17 +717,15 @@
expectVSyncSetEnabledCallReceived(true);
// Use the received callback to signal a first vsync event.
- // The interceptor should receive the event, but not the connection.
+ // The throttler should receive the event, but not the connection.
mCallback->onVSyncEvent(123, {456, 789});
- expectInterceptCallReceived(123);
expectThrottleVsyncReceived(456, mThrottledConnectionUid);
mThrottledConnectionEventCallRecorder.waitForUnexpectedCall();
// Use the received callback to signal a second vsync event.
- // The interceptor should receive the event, but the connection should
+ // The throttler should receive the event, but the connection should
// not as it was only interested in the first.
mCallback->onVSyncEvent(456, {123, 0});
- expectInterceptCallReceived(456);
expectThrottleVsyncReceived(123, mThrottledConnectionUid);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h
new file mode 100644
index 0000000..6ee4b9b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+namespace android {
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+using android::hardware::graphics::composer::hal::HWDisplayId;
+using android::Hwc2::mock::PowerAdvisor;
+
+struct FakeDisplayInjectorArgs {
+ uint8_t port = 255u;
+ HWDisplayId hwcDisplayId = 0;
+ bool isPrimary = true;
+};
+
+class FakeDisplayInjector {
+public:
+ FakeDisplayInjector(TestableSurfaceFlinger& flinger, Hwc2::mock::PowerAdvisor& powerAdvisor,
+ sp<mock::NativeWindow> nativeWindow)
+ : mFlinger(flinger), mPowerAdvisor(powerAdvisor), mNativeWindow(nativeWindow) {}
+
+ sp<DisplayDevice> injectInternalDisplay(
+ const std::function<void(FakeDisplayDeviceInjector&)>& injectExtra,
+ FakeDisplayInjectorArgs args = {}) {
+ using testing::_;
+ using testing::AnyNumber;
+ using testing::DoAll;
+ using testing::Mock;
+ using testing::Return;
+ using testing::SetArgPointee;
+
+ constexpr ui::Size kResolution = {1080, 1920};
+
+ // The DisplayDevice is required to have a framebuffer (behind the
+ // ANativeWindow interface) which uses the actual hardware display
+ // size.
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kResolution.getWidth()), Return(0)));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kResolution.getHeight()), Return(0)));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber());
+
+ auto compositionDisplay = compositionengine::impl::
+ createDisplay(mFlinger.getCompositionEngine(),
+ compositionengine::DisplayCreationArgsBuilder()
+ .setId(PhysicalDisplayId::fromPort(args.port))
+ .setPixels(kResolution)
+ .setPowerAdvisor(&mPowerAdvisor)
+ .build());
+
+ auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal,
+ args.hwcDisplayId, args.isPrimary);
+
+ injector.setNativeWindow(mNativeWindow);
+ if (injectExtra) {
+ injectExtra(injector);
+ }
+
+ auto displayDevice = injector.inject();
+
+ Mock::VerifyAndClear(mNativeWindow.get());
+
+ return displayDevice;
+ }
+
+ TestableSurfaceFlinger& mFlinger;
+ Hwc2::mock::PowerAdvisor& mPowerAdvisor;
+ sp<mock::NativeWindow> mNativeWindow;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 874fa7c..f47ac6d 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -480,7 +480,7 @@
addEmptyDisplayFrame();
auto displayFrame0 = getDisplayFrame(0);
- EXPECT_EQ(displayFrame0->getActuals().presentTime, -1);
+ EXPECT_EQ(displayFrame0->getActuals().presentTime, 59);
EXPECT_EQ(displayFrame0->getJankType(), JankType::Unknown);
EXPECT_EQ(surfaceFrame1->getActuals().presentTime, -1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::Unknown);
@@ -2228,6 +2228,50 @@
EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
}
+TEST_F(FrameTimelineTest, jankClassification_presentFenceError) {
+ auto erroneousPresentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto erroneousPresentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto validPresentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+ int64_t sfToken3 = mTokenManager->generateTokenForPredictions({72, 80, 80});
+
+ mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
+ mFrameTimeline->setSfPresent(26, erroneousPresentFence1);
+
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
+ mFrameTimeline->setSfPresent(60, erroneousPresentFence2);
+
+ mFrameTimeline->setSfWakeUp(sfToken3, 72, Fps::fromPeriodNsecs(11));
+ mFrameTimeline->setSfPresent(80, validPresentFence);
+
+ validPresentFence->signalForTest(80);
+
+ addEmptyDisplayFrame();
+
+ {
+ auto displayFrame = getDisplayFrame(0);
+ EXPECT_EQ(displayFrame->getActuals().presentTime, 26);
+ EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::UnknownPresent);
+ EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::UnknownFinish);
+ EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown);
+ }
+ {
+ auto displayFrame = getDisplayFrame(1);
+ EXPECT_EQ(displayFrame->getActuals().presentTime, 60);
+ EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::UnknownPresent);
+ EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::UnknownFinish);
+ EXPECT_EQ(displayFrame->getJankType(), JankType::Unknown);
+ }
+ {
+ auto displayFrame = getDisplayFrame(2);
+ EXPECT_EQ(displayFrame->getActuals().presentTime, 80);
+ EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
+ EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+ EXPECT_EQ(displayFrame->getJankType(), JankType::None);
+ }
+}
+
TEST_F(FrameTimelineTest, computeFps_noLayerIds_returnsZero) {
EXPECT_EQ(mFrameTimeline->computeFps({}), 0.0f);
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index a706c4b..620825f 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -34,6 +34,7 @@
namespace hal = android::hardware::graphics::composer::hal;
+using SetPolicyResult = RefreshRateConfigs::SetPolicyResult;
using LayerVoteType = RefreshRateConfigs::LayerVoteType;
using LayerRequirement = RefreshRateConfigs::LayerRequirement;
@@ -76,7 +77,9 @@
std::vector<RefreshRateRanking> getRefreshRatesByPolicy(
std::optional<int> anchorGroupOpt, RefreshRateOrder refreshRateOrder) const {
std::lock_guard lock(mLock);
- return RefreshRateConfigs::getRefreshRatesByPolicyLocked(anchorGroupOpt, refreshRateOrder);
+ return RefreshRateConfigs::
+ getRefreshRatesByPolicyLocked(anchorGroupOpt, refreshRateOrder,
+ /*preferredDisplayModeOpt*/ std::nullopt);
}
const std::vector<Fps>& knownFrameRates() const { return mKnownFrameRates; }
@@ -93,6 +96,15 @@
GlobalSignals signals = {}) const {
return getRankedRefreshRatesAndSignals(layers, signals).first.front().displayModePtr;
}
+
+ SetPolicyResult setPolicy(const PolicyVariant& policy) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ return RefreshRateConfigs::setPolicy(policy);
+ }
+
+ SetPolicyResult setDisplayManagerPolicy(const DisplayManagerPolicy& policy) {
+ return setPolicy(policy);
+ }
};
class RefreshRateConfigsTest : public testing::Test {
@@ -178,9 +190,33 @@
}
TEST_F(RefreshRateConfigsTest, invalidPolicy) {
- RefreshRateConfigs configs(kModes_60, kModeId60);
- EXPECT_LT(configs.setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}}), 0);
- EXPECT_LT(configs.setDisplayManagerPolicy({kModeId60, {20_Hz, 40_Hz}}), 0);
+ TestableRefreshRateConfigs configs(kModes_60, kModeId60);
+
+ EXPECT_EQ(SetPolicyResult::Invalid,
+ configs.setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}}));
+ EXPECT_EQ(SetPolicyResult::Invalid,
+ configs.setDisplayManagerPolicy({kModeId60, {20_Hz, 40_Hz}}));
+}
+
+TEST_F(RefreshRateConfigsTest, unchangedPolicy) {
+ TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
+
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
+
+ EXPECT_EQ(SetPolicyResult::Unchanged,
+ configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
+
+ // Override to the same policy.
+ EXPECT_EQ(SetPolicyResult::Unchanged,
+ configs.setPolicy(RefreshRateConfigs::OverridePolicy{kModeId90, {60_Hz, 90_Hz}}));
+
+ // Clear override to restore DisplayManagerPolicy.
+ EXPECT_EQ(SetPolicyResult::Unchanged,
+ configs.setPolicy(RefreshRateConfigs::NoOverridePolicy{}));
+
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {30_Hz, 90_Hz}}));
}
TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap) {
@@ -211,7 +247,8 @@
EXPECT_EQ(kMode60, minRate60);
EXPECT_EQ(kMode60, performanceRate60);
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
configs.setActiveModeId(kModeId90);
const auto minRate90 = configs.getMinRefreshRateByPolicy();
@@ -234,7 +271,8 @@
EXPECT_EQ(kMode60, minRate60);
EXPECT_EQ(kMode60, performanceRate60);
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
configs.setActiveModeId(kModeId90);
const auto minRate90 = configs.getMinRefreshRateByPolicy();
@@ -254,7 +292,8 @@
EXPECT_EQ(kMode60, minRate);
EXPECT_EQ(kMode90, performanceRate);
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
const auto minRate60 = configs.getMinRefreshRateByPolicy();
const auto performanceRate60 = configs.getMaxRefreshRateByPolicy();
@@ -276,7 +315,8 @@
EXPECT_EQ(mode.getId(), kModeId90);
}
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}));
{
const auto& mode = configs.getActiveMode();
EXPECT_EQ(mode.getId(), kModeId90);
@@ -291,19 +331,33 @@
// range.
EXPECT_EQ(kMode90, configs.getBestRefreshRate());
- EXPECT_EQ(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), NO_ERROR);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
EXPECT_EQ(kMode60, configs.getBestRefreshRate());
}
{
// We select max even when this will cause a non-seamless switch.
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
constexpr bool kAllowGroupSwitching = true;
- EXPECT_EQ(configs.setDisplayManagerPolicy({kModeId90, kAllowGroupSwitching, {0_Hz, 90_Hz}}),
- NO_ERROR);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy(
+ {kModeId90, kAllowGroupSwitching, {0_Hz, 90_Hz}}));
EXPECT_EQ(kMode90_G1, configs.getBestRefreshRate());
}
}
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_exactDontChangeRefreshRateWhenNotInPolicy) {
+ TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId72);
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ layers[0].vote = LayerVoteType::ExplicitExact;
+ layers[0].desiredRefreshRate = 120_Hz;
+
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId72, {0_Hz, 90_Hz}}));
+ EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers));
+}
+
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) {
TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
@@ -340,7 +394,8 @@
EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
lr.name = "";
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
lr.vote = LayerVoteType::Min;
EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
@@ -364,7 +419,8 @@
lr.desiredRefreshRate = 24_Hz;
EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}));
lr.vote = LayerVoteType::Min;
EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
@@ -388,7 +444,8 @@
lr.desiredRefreshRate = 24_Hz;
EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}}));
lr.vote = LayerVoteType::Min;
EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
@@ -1039,7 +1096,8 @@
RefreshRateRanking{kMode60},
RefreshRateRanking{kMode90}};
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}));
const std::vector<RefreshRateRanking>& refreshRates =
configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt,
@@ -1062,7 +1120,8 @@
RefreshRateRanking{kMode60},
RefreshRateRanking{kMode30}};
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}));
const std::vector<RefreshRateRanking>& refreshRates =
configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt,
@@ -1273,36 +1332,14 @@
EXPECT_EQ(lr.desiredRefreshRate, configs.getBestRefreshRate(layers)->getFps());
}
}
-
- // Test that 23.976 will choose 24 if 23.976 is not supported
- {
- TestableRefreshRateConfigs configs(makeModes(kMode24, kMode25, kMode30, kMode30Frac,
- kMode60, kMode60Frac),
- kModeId60);
-
- lr.vote = LayerVoteType::ExplicitExact;
- lr.desiredRefreshRate = 23.976_Hz;
- lr.name = "ExplicitExact 23.976 Hz";
- EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers)->getId());
- }
-
- // Test that 24 will choose 23.976 if 24 is not supported
- {
- TestableRefreshRateConfigs configs(makeModes(kMode24Frac, kMode25, kMode30, kMode30Frac,
- kMode60, kMode60Frac),
- kModeId60);
-
- lr.desiredRefreshRate = 24_Hz;
- lr.name = "ExplicitExact 24 Hz";
- EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers)->getId());
- }
}
TEST_F(RefreshRateConfigsTest,
getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) {
- RefreshRateConfigs configs(kModes_60_90, kModeId90);
+ TestableRefreshRateConfigs configs(kModes_60_90, kModeId90);
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}));
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
@@ -1323,7 +1360,8 @@
getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) {
TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}}));
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& lr = layers[0];
@@ -1472,7 +1510,8 @@
getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) {
TestableRefreshRateConfigs configs(kModes_60_90, kModeId90);
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}));
const auto [mode, signals] = configs.getRankedRefreshRatesAndSignals({}, {});
EXPECT_EQ(mode.front().displayModePtr, kMode90);
@@ -1546,10 +1585,10 @@
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) {
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
@@ -1564,10 +1603,10 @@
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) {
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
// Verify that we won't change the group if seamless switch is required.
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
@@ -1583,10 +1622,10 @@
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) {
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
configs.setActiveModeId(kModeId90);
@@ -1604,10 +1643,10 @@
TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) {
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
configs.setActiveModeId(kModeId90);
@@ -1628,10 +1667,10 @@
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) {
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
configs.setActiveModeId(kModeId90);
@@ -1657,10 +1696,10 @@
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) {
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
configs.setActiveModeId(kModeId90);
@@ -1690,10 +1729,10 @@
TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) {
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
configs.setActiveModeId(kModeId90);
@@ -1721,10 +1760,10 @@
TestableRefreshRateConfigs configs(kModes_30_60, kModeId60);
// Allow group switching.
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
auto& layer = layers[0];
@@ -1744,10 +1783,10 @@
TestableRefreshRateConfigs configs(kModes_25_30_50_60, kModeId60);
// Allow group switching.
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
std::vector<LayerRequirement> layers = {{.name = "60Hz ExplicitDefault",
.vote = LayerVoteType::ExplicitDefault,
@@ -1776,10 +1815,10 @@
TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId90);
// Allow group switching.
- RefreshRateConfigs::Policy policy;
+ RefreshRateConfigs::DisplayManagerPolicy policy;
policy.defaultMode = configs.getCurrentPolicy().defaultMode;
policy.allowGroupSwitching = true;
- EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+ EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
std::vector<LayerRequirement> layers = {
{.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}};
@@ -1807,7 +1846,8 @@
return configs.getBestRefreshRate(layers, {.touch = args.touch})->getId();
};
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}));
EXPECT_EQ(kModeId60, configs.getBestRefreshRate()->getId());
EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
@@ -1831,7 +1871,8 @@
EXPECT_EQ(kModeId60,
getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.touch = true}));
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}}));
EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Min, 90_Hz));
@@ -1860,7 +1901,8 @@
return refreshRate.front().displayModePtr->getId();
};
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}));
// Idle should be lower priority than touch boost.
{
@@ -2156,43 +2198,50 @@
TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) {
using KernelIdleTimerAction = RefreshRateConfigs::KernelIdleTimerAction;
- RefreshRateConfigs configs(kModes_60_90, kModeId90);
+ TestableRefreshRateConfigs configs(kModes_60_90, kModeId90);
- // SetPolicy(60, 90), current 90Hz => TurnOn.
+ // setPolicy(60, 90), current 90Hz => TurnOn.
EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction());
- // SetPolicy(60, 90), current 60Hz => TurnOn.
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}}), 0);
+ // setPolicy(60, 90), current 60Hz => TurnOn.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}}));
EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction());
- // SetPolicy(60, 60), current 60Hz => TurnOff
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
+ // setPolicy(60, 60), current 60Hz => TurnOff
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
- // SetPolicy(90, 90), current 90Hz => TurnOff.
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
+ // setPolicy(90, 90), current 90Hz => TurnOff.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}));
EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
}
TEST_F(RefreshRateConfigsTest, testKernelIdleTimerActionFor120Hz) {
using KernelIdleTimerAction = RefreshRateConfigs::KernelIdleTimerAction;
- RefreshRateConfigs configs(kModes_60_120, kModeId120);
+ TestableRefreshRateConfigs configs(kModes_60_120, kModeId120);
- // SetPolicy(0, 60), current 60Hz => TurnOn.
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 60_Hz}}), 0);
+ // setPolicy(0, 60), current 60Hz => TurnOn.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 60_Hz}}));
EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction());
- // SetPolicy(60, 60), current 60Hz => TurnOff.
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
+ // setPolicy(60, 60), current 60Hz => TurnOff.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
- // SetPolicy(60, 120), current 60Hz => TurnOn.
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 120_Hz}}), 0);
+ // setPolicy(60, 120), current 60Hz => TurnOn.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 120_Hz}}));
EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction());
- // SetPolicy(120, 120), current 120Hz => TurnOff.
- EXPECT_GE(configs.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}}), 0);
+ // setPolicy(120, 120), current 120Hz => TurnOff.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ configs.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}}));
EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
}
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 53e49eb..392398d 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -20,6 +20,7 @@
#include <mutex>
+#include "FakeDisplayInjector.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/RefreshRateConfigs.h"
#include "TestableScheduler.h"
@@ -40,6 +41,7 @@
using MockEventThread = android::mock::EventThread;
using MockLayer = android::mock::MockLayer;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u);
@@ -59,11 +61,14 @@
SchedulerTest();
- static inline const DisplayModePtr kMode60 = createDisplayMode(DisplayModeId(0), 60_Hz);
- static inline const DisplayModePtr kMode120 = createDisplayMode(DisplayModeId(1), 120_Hz);
+ static inline const DisplayModePtr kMode60_1 = createDisplayMode(DisplayModeId(0), 60_Hz);
+ static inline const DisplayModePtr kMode120_1 = createDisplayMode(DisplayModeId(1), 120_Hz);
+ static inline const DisplayModePtr kMode60_2 = createDisplayMode(DisplayModeId(2), 60_Hz);
+ static inline const DisplayModePtr kMode120_2 = createDisplayMode(DisplayModeId(3), 120_Hz);
+ static inline const DisplayModePtr kMode60_3 = createDisplayMode(DisplayModeId(4), 60_Hz);
std::shared_ptr<RefreshRateConfigs> mConfigs =
- std::make_shared<RefreshRateConfigs>(makeModes(kMode60), kMode60->getId());
+ std::make_shared<RefreshRateConfigs>(makeModes(kMode60_1), kMode60_1->getId());
mock::SchedulerCallback mSchedulerCallback;
TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback};
@@ -73,6 +78,10 @@
sp<MockEventThreadConnection> mEventThreadConnection;
TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::PowerAdvisor mPowerAdvisor;
+ sp<android::mock::NativeWindow> mNativeWindow = sp<android::mock::NativeWindow>::make();
+
+ FakeDisplayInjector mFakeDisplayInjector{mFlinger, mPowerAdvisor, mNativeWindow};
};
SchedulerTest::SchedulerTest() {
@@ -166,7 +175,7 @@
constexpr uint32_t kDisplayArea = 999'999;
mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
- EXPECT_CALL(mSchedulerCallback, requestDisplayMode(_, _)).Times(0);
+ EXPECT_CALL(mSchedulerCallback, requestDisplayModes(_)).Times(0);
mScheduler->chooseRefreshRateForContent();
}
@@ -176,7 +185,8 @@
ASSERT_EQ(1u, mScheduler->layerHistorySize());
mScheduler->setRefreshRateConfigs(
- std::make_shared<RefreshRateConfigs>(makeModes(kMode60, kMode120), kMode60->getId()));
+ std::make_shared<RefreshRateConfigs>(makeModes(kMode60_1, kMode120_1),
+ kMode60_1->getId()));
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
@@ -215,12 +225,17 @@
}
MATCHER(Is120Hz, "") {
- return isApproxEqual(arg->getFps(), 120_Hz);
+ return isApproxEqual(arg.front().displayModePtr->getFps(), 120_Hz);
}
TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
- mScheduler->setRefreshRateConfigs(
- std::make_shared<RefreshRateConfigs>(makeModes(kMode60, kMode120), kMode60->getId()));
+ auto display =
+ mFakeDisplayInjector.injectInternalDisplay([&](FakeDisplayDeviceInjector& injector) {
+ injector.setDisplayModes(makeModes(kMode60_1, kMode120_1), kMode60_1->getId());
+ });
+
+ mScheduler->registerDisplay(display);
+ mScheduler->setRefreshRateConfigs(display->holdRefreshRateConfigs());
const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true));
@@ -233,12 +248,138 @@
constexpr uint32_t kDisplayArea = 999'999;
mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
- EXPECT_CALL(mSchedulerCallback, requestDisplayMode(Is120Hz(), _)).Times(1);
+ EXPECT_CALL(mSchedulerCallback, requestDisplayModes(Is120Hz())).Times(1);
mScheduler->chooseRefreshRateForContent();
// No-op if layer requirements have not changed.
- EXPECT_CALL(mSchedulerCallback, requestDisplayMode(_, _)).Times(0);
+ EXPECT_CALL(mSchedulerCallback, requestDisplayModes(_)).Times(0);
mScheduler->chooseRefreshRateForContent();
}
+TEST_F(SchedulerTest, getBestDisplayMode_singleDisplay) {
+ auto display =
+ mFakeDisplayInjector.injectInternalDisplay([&](FakeDisplayDeviceInjector& injector) {
+ injector.setDisplayModes(makeModes(kMode60_1, kMode120_1), kMode60_1->getId());
+ });
+
+ mScheduler->registerDisplay(display);
+
+ std::vector<RefreshRateConfigs::LayerRequirement> layers =
+ std::vector<RefreshRateConfigs::LayerRequirement>({{.weight = 1.f}, {.weight = 1.f}});
+ mScheduler->setContentRequirements(layers);
+ GlobalSignals globalSignals = {.idle = true};
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+
+ std::vector<DisplayModeConfig> displayModeConfigs = mScheduler->getBestDisplayModeConfigs();
+ ASSERT_EQ(1ul, displayModeConfigs.size());
+ EXPECT_EQ(displayModeConfigs.front().displayModePtr, kMode60_1);
+ EXPECT_EQ(displayModeConfigs.front().signals, globalSignals);
+
+ globalSignals = {.idle = false};
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+ displayModeConfigs = mScheduler->getBestDisplayModeConfigs();
+ ASSERT_EQ(1ul, displayModeConfigs.size());
+ EXPECT_EQ(displayModeConfigs.front().displayModePtr, kMode120_1);
+ EXPECT_EQ(displayModeConfigs.front().signals, globalSignals);
+
+ globalSignals = {.touch = true};
+ mScheduler->replaceTouchTimer(10);
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+ displayModeConfigs = mScheduler->getBestDisplayModeConfigs();
+ ASSERT_EQ(1ul, displayModeConfigs.size());
+ EXPECT_EQ(displayModeConfigs.front().displayModePtr, kMode120_1);
+ EXPECT_EQ(displayModeConfigs.front().signals, globalSignals);
+
+ mScheduler->unregisterDisplay(display->getPhysicalId());
+ EXPECT_TRUE(mScheduler->mutableDisplays().empty());
+}
+
+TEST_F(SchedulerTest, getBestDisplayModes_multipleDisplays) {
+ auto display1 =
+ mFakeDisplayInjector.injectInternalDisplay([&](FakeDisplayDeviceInjector& injector) {
+ injector.setDisplayModes(makeModes(kMode60_1, kMode120_1), kMode60_1->getId());
+ });
+ auto display2 = mFakeDisplayInjector.injectInternalDisplay(
+ [&](FakeDisplayDeviceInjector& injector) {
+ injector.setDisplayModes(makeModes(kMode60_2, kMode120_2), kMode60_2->getId());
+ },
+ {.port = 253u, .hwcDisplayId = 42, .isPrimary = false});
+
+ mScheduler->registerDisplay(display1);
+ mScheduler->registerDisplay(display2);
+
+ std::vector<sp<DisplayDevice>> expectedDisplays = {display1, display2};
+ std::vector<RefreshRateConfigs::LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+ GlobalSignals globalSignals = {.idle = true};
+ std::vector<DisplayModeConfig> expectedConfigs = {DisplayModeConfig{globalSignals, kMode60_1},
+ DisplayModeConfig{globalSignals, kMode60_2}};
+
+ mScheduler->setContentRequirements(layers);
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+ std::vector<DisplayModeConfig> displayModeConfigs = mScheduler->getBestDisplayModeConfigs();
+ ASSERT_EQ(displayModeConfigs.size(), expectedConfigs.size());
+ for (size_t i = 0; i < expectedConfigs.size(); ++i) {
+ EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr)
+ << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue()
+ << " Actual fps "
+ << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue();
+ EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals);
+ }
+
+ expectedConfigs = std::vector<DisplayModeConfig>{DisplayModeConfig{globalSignals, kMode120_1},
+ DisplayModeConfig{globalSignals, kMode120_2}};
+
+ globalSignals = {.idle = false};
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+ displayModeConfigs = mScheduler->getBestDisplayModeConfigs();
+ ASSERT_EQ(expectedConfigs.size(), displayModeConfigs.size());
+ for (size_t i = 0; i < expectedConfigs.size(); ++i) {
+ EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr)
+ << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue()
+ << " Actual fps "
+ << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue();
+ EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals);
+ }
+
+ globalSignals = {.touch = true};
+ mScheduler->replaceTouchTimer(10);
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+ displayModeConfigs = mScheduler->getBestDisplayModeConfigs();
+ ASSERT_EQ(expectedConfigs.size(), displayModeConfigs.size());
+ for (size_t i = 0; i < expectedConfigs.size(); ++i) {
+ EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr)
+ << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue()
+ << " Actual fps "
+ << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue();
+ EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals);
+ }
+
+ // Filters out the 120Hz as it's not present on the display3, even with touch active
+ // we select 60Hz here.
+ auto display3 = mFakeDisplayInjector.injectInternalDisplay(
+ [&](FakeDisplayDeviceInjector& injector) {
+ injector.setDisplayModes(makeModes(kMode60_3), kMode60_3->getId());
+ },
+ {.port = 252u, .hwcDisplayId = 41, .isPrimary = false});
+
+ mScheduler->registerDisplay(display3);
+
+ expectedDisplays = {display1, display2, display3};
+ globalSignals = {.touch = true};
+ mScheduler->replaceTouchTimer(10);
+ expectedConfigs = std::vector<DisplayModeConfig>{DisplayModeConfig{globalSignals, kMode60_1},
+ DisplayModeConfig{globalSignals, kMode60_2},
+ DisplayModeConfig{globalSignals, kMode60_3}};
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+ displayModeConfigs = mScheduler->getBestDisplayModeConfigs();
+ ASSERT_EQ(expectedConfigs.size(), displayModeConfigs.size());
+ for (size_t i = 0; i < expectedConfigs.size(); ++i) {
+ EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr)
+ << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue()
+ << " Actual fps "
+ << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue();
+ EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals);
+ }
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index f7d34ac..6a9c970 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -30,9 +30,6 @@
// --------------------------------------------------------------------
// Call Expectations
- // The call should notify the interceptor that a display was created.
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-
// --------------------------------------------------------------------
// Invocation
@@ -61,9 +58,6 @@
// --------------------------------------------------------------------
// Call Expectations
- // The call should notify the interceptor that a display was created.
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-
// --------------------------------------------------------------------
// Invocation
int64_t oldId = IPCThreadState::self()->clearCallingIdentity();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
index 40ef949..93a3811 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
@@ -37,9 +37,6 @@
// --------------------------------------------------------------------
// Call Expectations
- // The call should notify the interceptor that a display was created.
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
-
// Destroying the display commits a display transaction.
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index 73f654b..94d517a 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -90,15 +90,12 @@
Case::HdrSupport::setupComposerCallExpectations(this);
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
expectHotplugReceived<Case, true>(mEventThread);
expectHotplugReceived<Case, true>(mSFEventThread);
}
template <typename Case>
void DisplayTransactionCommitTest::setupCommonCallExpectationsForDisconnectProcessing() {
- EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
-
expectHotplugReceived<Case, false>(mEventThread);
expectHotplugReceived<Case, false>(mSFEventThread);
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
index ec7e8a7..4e9f293 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
@@ -21,6 +21,7 @@
#include <thread>
#include "DisplayTransactionTestHelpers.h"
+#include "FakeDisplayInjector.h"
#include <android/hardware/power/Boost.h>
@@ -32,6 +33,8 @@
TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
using namespace std::chrono_literals;
+ injectDefaultInternalDisplay([](FakeDisplayDeviceInjector&) {});
+
mFlinger.scheduler()->replaceTouchTimer(100);
std::this_thread::sleep_for(10ms); // wait for callback to be triggered
EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index 98249bf..f553a23 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -38,11 +38,6 @@
// --------------------------------------------------------------------
// Call Expectations
- // We expect the surface interceptor to possibly be used, but we treat it as
- // disabled since it is called as a side effect rather than directly by this
- // function.
- EXPECT_CALL(*mSurfaceInterceptor, isEnabled()).WillOnce(Return(false));
-
// We expect a call to get the active display config.
Case::Display::setupHwcGetActiveConfigCallExpectations(this);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index e256d2c..bc66961 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -97,7 +97,7 @@
.setNativeWindow(mNativeWindow)
.setPowerMode(hal::PowerMode::ON)
.inject();
- mFlinger.mutableActiveDisplayToken() = mDisplay->getDisplayToken();
+ mFlinger.mutableActiveDisplayId() = mDisplay->getPhysicalId();
}
void SurfaceFlingerPowerHintTest::setupScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 9e54083..25857ec 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -262,7 +262,7 @@
if (injector.physicalDisplay()
.transform(&display::PhysicalDisplay::isInternal)
.value_or(false)) {
- test->mFlinger.mutableActiveDisplayToken() = display->getDisplayToken();
+ test->mFlinger.mutableActiveDisplayId() = display->getPhysicalId();
}
return display;
@@ -276,13 +276,6 @@
EXPECT_CALL(*test->mFlinger.scheduler(), scheduleFrame()).Times(1);
}
- static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
- PowerMode mode) {
- EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
- EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, static_cast<int32_t>(mode)))
- .Times(1);
- }
-
static void setupComposerCallExpectations(DisplayTransactionTest* test, PowerMode mode) {
// Any calls to get the active config will return a default value.
EXPECT_CALL(*test->mComposer, getActiveConfig(Display::HWC_DISPLAY_ID, _))
@@ -349,7 +342,6 @@
// --------------------------------------------------------------------
// Call Expectations
- Case::setupSurfaceInterceptorCallExpectations(this, Case::Transition::TARGET_POWER_MODE);
Case::Transition::template setupCallExpectations<Case>(this);
// --------------------------------------------------------------------
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 073c459..0384568 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -36,16 +36,13 @@
static constexpr bool WIDE_COLOR_SUPPORTED = true;
static void injectConfigChange(DisplayTransactionTest* test) {
- test->mFlinger.mutableHasWideColorDisplay() = true;
+ test->mFlinger.mutableSupportsWideColor() = true;
test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_DATASPACE)).Times(1);
- EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})),
- Return(Error::NONE)));
EXPECT_CALL(*test->mComposer,
getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _))
.WillOnce(DoAll(SetArgPointee<2>(
@@ -253,9 +250,15 @@
.hwcDisplayId = *hwcDisplayId,
.activeMode = activeMode};
+ ui::ColorModes colorModes;
+ if constexpr (Case::WideColorSupport::WIDE_COLOR_SUPPORTED) {
+ colorModes.push_back(ColorMode::DISPLAY_P3);
+ }
+
mFlinger.mutablePhysicalDisplays().emplace_or_replace(*displayId, displayToken, *displayId,
*connectionType,
- makeModes(activeMode), std::nullopt);
+ makeModes(activeMode),
+ std::move(colorModes), std::nullopt);
}
state.isSecure = static_cast<bool>(Case::Display::SECURE);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp
new file mode 100644
index 0000000..0cf3bdf
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp
@@ -0,0 +1,212 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockVsyncController.h"
+
+namespace android {
+
+using testing::_;
+using testing::Return;
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+class SurfaceFlingerUpdateLayerMetadataSnapshotTest : public testing::Test {
+public:
+ SurfaceFlingerUpdateLayerMetadataSnapshotTest() { setupScheduler(); }
+
+protected:
+ void setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
+
+ auto vsyncController = std::make_unique<mock::VsyncController>();
+ auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+ std::move(eventThread), std::move(sfEventThread));
+ }
+
+ sp<Layer> createLayer(const char* name, LayerMetadata layerMetadata) {
+ return sp<Layer>::make(
+ LayerCreationArgs{mFlinger.flinger(), nullptr, name, 0, layerMetadata});
+ }
+
+ TestableSurfaceFlinger mFlinger;
+};
+
+class LayerMetadataBuilder {
+public:
+ LayerMetadataBuilder(LayerMetadata layerMetadata = {}) : mLayerMetadata(layerMetadata) {}
+
+ LayerMetadataBuilder& setInt32(uint32_t key, int32_t value) {
+ mLayerMetadata.setInt32(key, value);
+ return *this;
+ }
+
+ LayerMetadata build() { return mLayerMetadata; }
+
+private:
+ LayerMetadata mLayerMetadata;
+};
+
+bool operator==(const LayerMetadata& lhs, const LayerMetadata& rhs) {
+ return lhs.mMap == rhs.mMap;
+}
+
+std::ostream& operator<<(std::ostream& stream, const LayerMetadata& layerMetadata) {
+ stream << "LayerMetadata{";
+ for (auto it = layerMetadata.mMap.cbegin(); it != layerMetadata.mMap.cend(); it++) {
+ if (it != layerMetadata.mMap.cbegin()) {
+ stream << ", ";
+ }
+ stream << layerMetadata.itemToString(it->first, ":");
+ }
+ return stream << "}";
+}
+
+// Test that the snapshot's layer metadata is set.
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesSnapshotMetadata) {
+ auto layerMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 1).build();
+ auto layer = createLayer("layer", layerMetadata);
+ mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
+
+ mFlinger.updateLayerMetadataSnapshot();
+
+ ASSERT_EQ(layer->getLayerSnapshot()->layerMetadata, layerMetadata);
+}
+
+// Test that snapshot layer metadata is set by merging the child's metadata on top of its
+// parent's metadata.
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, mergesSnapshotMetadata) {
+ auto layerAMetadata = LayerMetadataBuilder()
+ .setInt32(METADATA_OWNER_UID, 1)
+ .setInt32(METADATA_TASK_ID, 2)
+ .build();
+ auto layerA = createLayer("parent", layerAMetadata);
+ auto layerBMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 3).build();
+ auto layerB = createLayer("child", layerBMetadata);
+ layerA->addChild(layerB);
+ layerA->commitChildList();
+ mFlinger.mutableDrawingState().layersSortedByZ.add(layerA);
+
+ mFlinger.updateLayerMetadataSnapshot();
+
+ ASSERT_EQ(layerA->getLayerSnapshot()->layerMetadata, layerAMetadata);
+ auto expectedChildMetadata =
+ LayerMetadataBuilder(layerAMetadata).setInt32(METADATA_TASK_ID, 3).build();
+ ASSERT_EQ(layerB->getLayerSnapshot()->layerMetadata, expectedChildMetadata);
+}
+
+// Test that snapshot relative layer metadata is set to the parent's layer metadata merged on top of
+// that parent's relative layer metadata.
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesRelativeMetadata) {
+ auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 1).build();
+ auto layerA = createLayer("relative-parent", layerAMetadata);
+ auto layerAHandle = layerA->getHandle();
+ auto layerBMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 2).build();
+ auto layerB = createLayer("relative-child", layerBMetadata);
+ layerB->setRelativeLayer(layerAHandle, 1);
+ mFlinger.mutableDrawingState().layersSortedByZ.add(layerA);
+ mFlinger.mutableDrawingState().layersSortedByZ.add(layerB);
+
+ mFlinger.updateLayerMetadataSnapshot();
+
+ ASSERT_EQ(layerA->getLayerSnapshot()->relativeLayerMetadata, LayerMetadata{});
+ ASSERT_EQ(layerB->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata);
+}
+
+// Test that snapshot relative layer metadata is set correctly when a layer is interleaved within
+// two other layers.
+//
+// Layer
+// A
+// / \
+// B D
+// /
+// C
+//
+// Z-order Relatives
+// B <- D <- C
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesRelativeMetadataInterleaved) {
+ auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_OWNER_UID, 1).build();
+ auto layerA = createLayer("layer-a", layerAMetadata);
+ auto layerBMetadata = LayerMetadataBuilder()
+ .setInt32(METADATA_TASK_ID, 2)
+ .setInt32(METADATA_OWNER_PID, 3)
+ .build();
+ auto layerB = createLayer("layer-b", layerBMetadata);
+ auto layerBHandle = layerB->getHandle();
+ auto layerC = createLayer("layer-c", {});
+ auto layerDMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 4).build();
+ auto layerD = createLayer("layer-d", layerDMetadata);
+ auto layerDHandle = layerD->getHandle();
+ layerB->addChild(layerC);
+ layerA->addChild(layerB);
+ layerA->addChild(layerD);
+ layerC->setRelativeLayer(layerDHandle, 1);
+ layerD->setRelativeLayer(layerBHandle, 1);
+ layerA->commitChildList();
+ mFlinger.mutableDrawingState().layersSortedByZ.add(layerA);
+
+ mFlinger.updateLayerMetadataSnapshot();
+
+ auto expectedLayerDRelativeMetadata = LayerMetadataBuilder()
+ // From layer A, parent of relative parent
+ .setInt32(METADATA_OWNER_UID, 1)
+ // From layer B, relative parent
+ .setInt32(METADATA_TASK_ID, 2)
+ .setInt32(METADATA_OWNER_PID, 3)
+ .build();
+ ASSERT_EQ(layerD->getLayerSnapshot()->relativeLayerMetadata, expectedLayerDRelativeMetadata);
+ auto expectedLayerCRelativeMetadata =
+ LayerMetadataBuilder()
+ // From layer A, parent of relative parent
+ .setInt32(METADATA_OWNER_UID, 1)
+ // From layer B, relative parent of relative parent
+ .setInt32(METADATA_OWNER_PID, 3)
+ // From layer D, relative parent
+ .setInt32(METADATA_TASK_ID, 4)
+ .build();
+ ASSERT_EQ(layerC->getLayerSnapshot()->relativeLayerMetadata, expectedLayerCRelativeMetadata);
+}
+
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest,
+ updatesRelativeMetadataMultipleRelativeChildren) {
+ auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_OWNER_UID, 1).build();
+ auto layerA = createLayer("layer-a", layerAMetadata);
+ auto layerAHandle = layerA->getHandle();
+ auto layerB = createLayer("layer-b", {});
+ auto layerC = createLayer("layer-c", {});
+ layerB->setRelativeLayer(layerAHandle, 1);
+ layerC->setRelativeLayer(layerAHandle, 2);
+ layerA->commitChildList();
+ mFlinger.mutableDrawingState().layersSortedByZ.add(layerA);
+ mFlinger.mutableDrawingState().layersSortedByZ.add(layerB);
+ mFlinger.mutableDrawingState().layersSortedByZ.add(layerC);
+
+ mFlinger.updateLayerMetadataSnapshot();
+
+ ASSERT_EQ(layerA->getLayerSnapshot()->relativeLayerMetadata, LayerMetadata{});
+ ASSERT_EQ(layerB->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata);
+ ASSERT_EQ(layerC->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 93e3059..68df987 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -68,6 +68,8 @@
auto& mutableLayerHistory() { return mLayerHistory; }
+ auto& mutableDisplays() { return mDisplays; }
+
size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size();
}
@@ -94,6 +96,22 @@
return mPolicy.touch == Scheduler::TouchState::Active;
}
+ void setTouchStateAndIdleTimerPolicy(GlobalSignals globalSignals) {
+ std::lock_guard<std::mutex> lock(mPolicyLock);
+ mPolicy.touch = globalSignals.touch ? TouchState::Active : TouchState::Inactive;
+ mPolicy.idleTimer = globalSignals.idle ? TimerState::Expired : TimerState::Reset;
+ }
+
+ void setContentRequirements(std::vector<RefreshRateConfigs::LayerRequirement> layers) {
+ std::lock_guard<std::mutex> lock(mPolicyLock);
+ mPolicy.contentRequirements = std::move(layers);
+ }
+
+ std::vector<DisplayModeConfig> getBestDisplayModeConfigs() {
+ std::lock_guard<std::mutex> lock(mPolicyLock);
+ return Scheduler::getBestDisplayModeConfigs();
+ }
+
void dispatchCachedReportedMode() {
std::lock_guard<std::mutex> lock(mPolicyLock);
return Scheduler::dispatchCachedReportedMode();
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2c9c451..29ff5ee 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -40,7 +40,6 @@
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerDefaultFactory.h"
-#include "SurfaceInterceptor.h"
#include "TestableScheduler.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
@@ -81,10 +80,6 @@
return std::make_unique<scheduler::FakePhaseOffsets>();
}
- sp<SurfaceInterceptor> createSurfaceInterceptor() override {
- return sp<android::impl::SurfaceInterceptor>::make();
- }
-
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
return sp<StartPropertySetThread>::make(timestampPropertyValue);
}
@@ -158,7 +153,6 @@
if (!mFlinger) {
mFlinger = sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
}
- mFlinger->mAnimationTransactionTimeout = ms2ns(10);
}
SurfaceFlinger* flinger() { return mFlinger.get(); }
@@ -418,9 +412,13 @@
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
- auto& getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; }
- auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
- auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; }
+ auto& getTransactionQueue() { return mFlinger->mTransactionHandler.mLocklessTransactionQueue; }
+ auto& getPendingTransactionQueue() {
+ return mFlinger->mTransactionHandler.mPendingTransactionQueues;
+ }
+ size_t getPendingTransactionCount() {
+ return mFlinger->mTransactionHandler.mPendingTransactionCount.load();
+ }
auto setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
@@ -465,18 +463,18 @@
mFlinger->onActiveDisplayChangedLocked(activeDisplay);
}
- auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
- const sp<IBinder>& parentHandle, int32_t* outLayerId,
- const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
- return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, parentLayer,
- outTransformHint);
+ auto createLayer(LayerCreationArgs& args, const sp<IBinder>& parentHandle,
+ gui::CreateSurfaceResult& outResult) {
+ return mFlinger->createLayer(args, parentHandle, outResult);
}
auto mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
- sp<IBinder>* outHandle, int32_t* outLayerId) {
- return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
+ gui::CreateSurfaceResult& outResult) {
+ return mFlinger->mirrorLayer(args, mirrorFromHandle, outResult);
}
+ void updateLayerMetadataSnapshot() { mFlinger->updateLayerMetadataSnapshot(); }
+
/* ------------------------------------------------------------------------
* Read-only access to private data to assert post-conditions.
*/
@@ -491,10 +489,6 @@
return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get());
}
- nsecs_t getAnimationTransactionTimeout() const {
- return mFlinger->mAnimationTransactionTimeout;
- }
-
/* ------------------------------------------------------------------------
* Read-write access to private data to set up preconditions and assert
* post-conditions.
@@ -509,7 +503,7 @@
const auto& hwcPhysicalDisplayIdMap() const { return getHwComposer().mPhysicalDisplayIdMap; }
const auto& hwcDisplayData() const { return getHwComposer().mDisplayData; }
- auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
+ auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
@@ -517,7 +511,6 @@
auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; }
- auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
@@ -528,7 +521,7 @@
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; }
- auto& mutableActiveDisplayToken() { return mFlinger->mActiveDisplayToken; }
+ auto& mutableActiveDisplayId() { return mFlinger->mActiveDisplayId; }
auto fromHandle(const sp<IBinder>& handle) {
return mFlinger->fromHandle(handle);
@@ -542,7 +535,6 @@
mutableDisplays().clear();
mutableCurrentState().displays.clear();
mutableDrawingState().displays.clear();
- mutableInterceptor().clear();
mFlinger->mScheduler.reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mCompositionEngine->setRenderEngine(
@@ -841,6 +833,9 @@
sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs);
mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display);
+ if (mFlinger.scheduler()) {
+ mFlinger.scheduler()->registerDisplay(display);
+ }
DisplayDeviceState state;
state.isSecure = mCreationArgs.isSecure;
@@ -861,7 +856,7 @@
const auto it = mFlinger.mutablePhysicalDisplays()
.emplace_or_replace(*physicalId, mDisplayToken, *physicalId,
*mConnectionType, std::move(modes),
- std::nullopt)
+ ui::ColorModes(), std::nullopt)
.first;
display->setActiveMode(activeModeId, it->second.snapshot());
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index b493d11..db438b7 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
@@ -22,12 +21,17 @@
#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <gui/LayerState.h>
#include <gui/SurfaceComposerClient.h>
+#include <gui/fake/BufferData.h>
#include <log/log.h>
#include <ui/MockFence.h>
#include <utils/String8.h>
+#include <vector>
+#include <binder/Binder.h>
#include "TestableSurfaceFlinger.h"
+#include "TransactionHandler.h"
#include "mock/MockEventThread.h"
#include "mock/MockVsyncController.h"
@@ -37,7 +41,7 @@
using testing::Return;
using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
-
+constexpr nsecs_t TRANSACTION_TIMEOUT = s2ns(5);
class TransactionApplicationTest : public testing::Test {
public:
TransactionApplicationTest() {
@@ -78,6 +82,7 @@
mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
std::move(eventThread), std::move(sfEventThread));
+ mFlinger.flinger()->addTransactionReadyFilters();
}
TestableSurfaceFlinger mFlinger;
@@ -112,7 +117,7 @@
void setupSingle(TransactionInfo& transaction, uint32_t flags, int64_t desiredPresentTime,
bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo) {
mTransactionNumber++;
- transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
+ transaction.flags |= flags;
transaction.desiredPresentTime = desiredPresentTime;
transaction.isAutoTimestamp = isAutoTimestamp;
transaction.frameTimelineInfo = frameTimelineInfo;
@@ -136,11 +141,7 @@
// If transaction is synchronous, SF applyTransactionState should time out (5s) wating for
// SF to commit the transaction. If this is animation, it should not time out waiting.
nsecs_t returnedTime = systemTime();
- if (flags & ISurfaceComposer::eSynchronous) {
- EXPECT_GE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
- } else {
- EXPECT_LE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
- }
+ EXPECT_LE(returnedTime, applicationTime + TRANSACTION_TIMEOUT);
// Each transaction should have been placed on the transaction queue
auto& transactionQueue = mFlinger.getTransactionQueue();
EXPECT_FALSE(transactionQueue.isEmpty());
@@ -165,13 +166,7 @@
transaction.id);
nsecs_t returnedTime = systemTime();
- if (flags & ISurfaceComposer::eSynchronous) {
- EXPECT_GE(systemTime(),
- applicationSentTime + mFlinger.getAnimationTransactionTimeout());
- } else {
- EXPECT_LE(returnedTime,
- applicationSentTime + mFlinger.getAnimationTransactionTimeout());
- }
+ EXPECT_LE(returnedTime, applicationSentTime + TRANSACTION_TIMEOUT);
// This transaction should have been placed on the transaction queue
auto& transactionQueue = mFlinger.getTransactionQueue();
EXPECT_FALSE(transactionQueue.isEmpty());
@@ -204,7 +199,7 @@
// This thread should not have been blocked by the above transaction
// (5s is the timeout period that applyTransactionState waits for SF to
// commit the transaction)
- EXPECT_LE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout());
+ EXPECT_LE(systemTime(), applicationSentTime + TRANSACTION_TIMEOUT);
// transaction that would goes to pending transaciton queue.
mFlinger.flushTransactionQueues();
@@ -220,13 +215,7 @@
// if this is an animation, this thread should be blocked for 5s
// in setTransactionState waiting for transactionA to flush. Otherwise,
// the transaction should be placed on the pending queue
- if (flags & ISurfaceComposer::eSynchronous) {
- EXPECT_GE(systemTime(),
- applicationSentTime + mFlinger.getAnimationTransactionTimeout());
- } else {
- EXPECT_LE(systemTime(),
- applicationSentTime + mFlinger.getAnimationTransactionTimeout());
- }
+ EXPECT_LE(systemTime(), applicationSentTime + TRANSACTION_TIMEOUT);
// transaction that would goes to pending transaciton queue.
mFlinger.flushTransactionQueues();
@@ -294,26 +283,14 @@
EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
}
-TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
- NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous);
-}
-
TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) {
NotPlacedOnTransactionQueue(/*flags*/ 0);
}
-TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) {
- PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous);
-}
-
TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) {
PlaceOnTransactionQueue(/*flags*/ 0);
}
-TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) {
- BlockedByPriorTransaction(ISurfaceComposer::eSynchronous);
-}
-
TEST_F(TransactionApplicationTest, FromHandle) {
sp<IBinder> badHandle;
auto ret = mFlinger.fromHandle(badHandle);
@@ -329,7 +306,6 @@
mFlinger.getTransactionQueue().pop();
}
mFlinger.getPendingTransactionQueue().clear();
- mFlinger.getTransactionCommittedSignals().clear();
mFlinger.commitTransactionsLocked(eTransactionMask);
mFlinger.mutableCurrentState().layersSortedByZ.clear();
mFlinger.mutableDrawingState().layersSortedByZ.clear();
@@ -343,7 +319,10 @@
ComposerState createComposerState(int layerId, sp<Fence> fence, uint64_t what) {
ComposerState state;
- state.state.bufferData = std::make_shared<BufferData>();
+ state.state.bufferData =
+ std::make_shared<fake::BufferData>(/* bufferId */ 123L, /* width */ 1,
+ /* height */ 2, /* pixelFormat */ 0,
+ /* outUsage */ 0);
state.state.bufferData->acquireFence = std::move(fence);
state.state.layerId = layerId;
state.state.surface =
@@ -361,7 +340,7 @@
TransactionInfo createTransactionInfo(const sp<IBinder>& applyToken,
const std::vector<ComposerState>& states) {
TransactionInfo transaction;
- const uint32_t kFlags = ISurfaceComposer::eSynchronous;
+ const uint32_t kFlags = 0;
const nsecs_t kDesiredPresentTime = systemTime();
const bool kIsAutoTimestamp = true;
const auto kFrameTimelineInfo = FrameTimelineInfo{};
@@ -376,7 +355,6 @@
}
void setTransactionStates(const std::vector<TransactionInfo>& transactions,
- size_t expectedTransactionsApplied,
size_t expectedTransactionsPending) {
EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
@@ -391,8 +369,7 @@
}
mFlinger.flushTransactionQueues();
EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
- EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size());
- EXPECT_EQ(expectedTransactionsApplied, mFlinger.getTransactionCommittedSignals().size());
+ EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionCount());
}
};
@@ -408,22 +385,19 @@
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
createTransactionInfo(kApplyToken,
{createComposerState(kLayerId, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSingleUnSignaledFromTheQueue) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
@@ -433,33 +407,13 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
- const auto kExpectedTransactionsPending = 1u;
-
- const auto unsignaledTransaction =
- createTransactionInfo(kApplyToken,
- {
- createComposerState(kLayerId,
- fence(Fence::Status::Unsignaled),
- layer_state_t::eCropChanged),
- });
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
-}
-
-TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed) {
- const sp<IBinder> kApplyToken =
- IInterface::asBinder(TransactionCompletedListener::getIInstance());
- const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -471,15 +425,31 @@
layer_state_t::
eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
+}
+
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed) {
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eCropChanged |
+ layer_state_t::
+ eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueueSameApplyTokenMultiState) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto mixedTransaction =
@@ -492,8 +462,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueue_MultipleStateTransaction) {
@@ -501,7 +470,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto mixedTransaction =
@@ -514,8 +482,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSignaledFromTheQueue) {
@@ -523,7 +490,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
@@ -540,8 +506,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest,
@@ -552,7 +517,6 @@
const sp<IBinder> kApplyToken3 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -579,43 +543,7 @@
});
setTransactionStates({unsignaledTransaction, signaledTransaction, signaledTransaction2},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
-}
-
-TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_SignaledFirst) {
- const sp<IBinder> kApplyToken1 =
- IInterface::asBinder(TransactionCompletedListener::getIInstance());
- const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
- const sp<IBinder> kApplyToken3 = sp<BBinder>::make();
- const auto kLayerId1 = 1;
- const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
- const auto kExpectedTransactionsPending = 1u;
-
- const auto signaledTransaction =
- createTransactionInfo(kApplyToken1,
- {
- createComposerState(kLayerId1,
- fence(Fence::Status::Signaled),
- layer_state_t::eBufferChanged),
- });
- const auto signaledTransaction2 =
- createTransactionInfo(kApplyToken2,
- {
- createComposerState(kLayerId1,
- fence(Fence::Status::Signaled),
- layer_state_t::eBufferChanged),
- });
- const auto unsignaledTransaction =
- createTransactionInfo(kApplyToken3,
- {
- createComposerState(kLayerId2,
- fence(Fence::Status::Unsignaled),
- layer_state_t::eBufferChanged),
- });
-
- setTransactionStates({signaledTransaction, signaledTransaction2, unsignaledTransaction},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) {
@@ -623,7 +551,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -640,7 +567,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({unsignaledTransaction, signaledTransaction},
kExpectedTransactionsPending);
}
@@ -650,7 +577,6 @@
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -668,14 +594,13 @@
layer_state_t::eBufferChanged),
});
setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAutoSingleLayerTest, DontLatchUnsignaledWhenEarlyOffset) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -689,8 +614,7 @@
// Get VsyncModulator out of the default config
static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
class LatchUnsignaledDisabledTest : public LatchUnsignaledTest {
@@ -705,22 +629,19 @@
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
createTransactionInfo(kApplyToken,
{createComposerState(kLayerId, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueue) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -730,15 +651,13 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueSameLayerId) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -751,8 +670,7 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueDifferentLayerId) {
@@ -760,7 +678,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 0u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -773,8 +690,7 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) {
@@ -782,7 +698,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
@@ -799,8 +714,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheQueueDifferentApplyToken) {
@@ -809,7 +723,6 @@
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 1u;
const auto unsignaledTransaction =
@@ -826,7 +739,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({unsignaledTransaction, signaledTransaction},
kExpectedTransactionsPending);
}
@@ -835,7 +748,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 1u;
const auto signaledTransaction =
@@ -852,7 +764,7 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({signaledTransaction, unsignaledTransaction},
kExpectedTransactionsPending);
}
@@ -861,8 +773,7 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 0u;
- const auto kExpectedTransactionsPending = 1u;
+ const auto kExpectedTransactionsPending = 2u;
const auto unsignaledTransaction =
createTransactionInfo(kApplyToken,
@@ -879,7 +790,7 @@
layer_state_t::eBufferChanged),
});
setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
class LatchUnsignaledAlwaysTest : public LatchUnsignaledTest {
@@ -894,37 +805,32 @@
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
createTransactionInfo(kApplyToken,
{createComposerState(kLayerId, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueue) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
createTransactionInfo(kApplyToken,
{createComposerState(kLayerId, fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueSameLayerId) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto mixedTransaction =
@@ -933,8 +839,7 @@
layer_state_t::eBufferChanged),
createComposerState(kLayerId, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentLayerId) {
@@ -942,7 +847,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto mixedTransaction =
@@ -951,8 +855,7 @@
layer_state_t::eBufferChanged),
createComposerState(kLayerId2, fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged)});
- setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({mixedTransaction}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) {
@@ -960,7 +863,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
@@ -977,8 +879,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentApplyToken) {
@@ -987,7 +888,6 @@
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto signaledTransaction =
@@ -1004,7 +904,7 @@
fence(Fence::Status::Unsignaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({signaledTransaction, unsignaledTransaction},
kExpectedTransactionsPending);
}
@@ -1013,7 +913,6 @@
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
@@ -1030,7 +929,7 @@
fence(Fence::Status::Signaled),
layer_state_t::eBufferChanged),
});
- setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+ setTransactionStates({unsignaledTransaction, signaledTransaction},
kExpectedTransactionsPending);
}
@@ -1040,7 +939,6 @@
const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
const auto kLayerId1 = 1;
const auto kLayerId2 = 2;
- const auto kExpectedTransactionsApplied = 2u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
@@ -1058,14 +956,13 @@
layer_state_t::eBufferChanged),
});
setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
- kExpectedTransactionsApplied, kExpectedTransactionsPending);
+ kExpectedTransactionsPending);
}
TEST_F(LatchUnsignaledAlwaysTest, LatchUnsignaledWhenEarlyOffset) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
const auto kLayerId = 1;
- const auto kExpectedTransactionsApplied = 1u;
const auto kExpectedTransactionsPending = 0u;
const auto unsignaledTransaction =
@@ -1079,8 +976,19 @@
// Get VsyncModulator out of the default config
static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
- setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
- kExpectedTransactionsPending);
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
+}
+
+TEST(TransactionHandlerTest, QueueTransaction) {
+ TransactionHandler handler;
+ TransactionState transaction;
+ transaction.applyToken = sp<BBinder>::make();
+ transaction.id = 42;
+ handler.queueTransaction(std::move(transaction));
+ std::vector<TransactionState> transactionsReadyToBeApplied = handler.flushTransactions();
+
+ EXPECT_EQ(transactionsReadyToBeApplied.size(), 1u);
+ EXPECT_EQ(transactionsReadyToBeApplied.front().id, 42u);
}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index 1f011be..14e1aac 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -49,7 +49,8 @@
ComposerState s;
if (i == 1) {
layer.parentSurfaceControlForChild =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), layerHandle, 42);
+ sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), layerHandle, 42,
+ "#42");
}
s.state = layer;
t1.states.add(s);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 5267586..8af2dfa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -24,14 +24,14 @@
struct SchedulerCallback final : ISchedulerCallback {
MOCK_METHOD(void, setVsyncEnabled, (bool), (override));
- MOCK_METHOD(void, requestDisplayMode, (DisplayModePtr, DisplayModeEvent), (override));
+ MOCK_METHOD(void, requestDisplayModes, (std::vector<scheduler::DisplayModeConfig>), (override));
MOCK_METHOD(void, kernelTimerChanged, (bool), (override));
MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override));
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
void setVsyncEnabled(bool) override {}
- void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override {}
+ void requestDisplayModes(std::vector<scheduler::DisplayModeConfig>) override {}
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() override {}
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
deleted file mode 100644
index 0a0e7b5..0000000
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2018 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"
-
-#include "mock/MockSurfaceInterceptor.h"
-
-namespace android::mock {
-
-// Explicit default instantiation is recommended.
-SurfaceInterceptor::SurfaceInterceptor() = default;
-SurfaceInterceptor::~SurfaceInterceptor() = default;
-
-} // namespace android::mock
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
deleted file mode 100644
index b085027..0000000
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 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 <gmock/gmock.h>
-
-#include "SurfaceInterceptor.h"
-
-namespace android::mock {
-
-class SurfaceInterceptor : public android::SurfaceInterceptor {
-public:
- SurfaceInterceptor();
- ~SurfaceInterceptor() override;
-
- MOCK_METHOD2(enable,
- void(const SortedVector<sp<Layer>>&,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&));
- MOCK_METHOD0(disable, void());
- MOCK_METHOD0(isEnabled, bool());
- MOCK_METHOD1(addTransactionTraceListener, void(const sp<gui::ITransactionTraceListener>&));
- MOCK_METHOD1(binderDied, void(const wp<IBinder>&));
- MOCK_METHOD7(saveTransaction,
- void(const Vector<ComposerState>&,
- const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&,
- const Vector<DisplayState>&, uint32_t, int, int, uint64_t));
- MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
- MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
- MOCK_METHOD4(saveBufferUpdate, void(int32_t, uint32_t, uint32_t, uint64_t));
- MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&));
- MOCK_METHOD1(saveDisplayDeletion, void(int32_t));
- MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t));
- MOCK_METHOD1(saveVSyncEvent, void(nsecs_t));
-};
-
-} // namespace android::mock
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index 224868c..f297da5 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -51,7 +51,11 @@
}
static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
- captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
+ const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ // TODO(b/248317436): extend to cover all displays for multi-display devices
+ const auto display =
+ ids.empty() ? nullptr : SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
+ captureScreen(sc, display);
}
static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 9c6d19f..abcac3c 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -668,10 +668,11 @@
// VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following
// four values cannot be known without a surface. Default values will
// be supplied anyway, but cannot be relied upon.
- width = 1000;
- height = 1000;
- transform_hint = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- max_buffer_count = 10;
+ width = 0xFFFFFFFF;
+ height = 0xFFFFFFFF;
+ transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
+ capabilities->minImageCount = 0xFFFFFFFF;
+ capabilities->maxImageCount = 0xFFFFFFFF;
} else {
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -703,9 +704,9 @@
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
+ capabilities->minImageCount = std::min(max_buffer_count, 3);
+ capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
}
- capabilities->minImageCount = std::min(max_buffer_count, 3);
- capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
capabilities->currentExtent =
VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};