Merge "Add Unit Tests to Check Default Strategy Setup"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0b69829..fe91341 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"
@@ -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) {
@@ -1890,6 +1895,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));
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 0727383..a99ccae 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -326,16 +326,41 @@
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) {
+ LOG(WARNING) << "Service '" << name << "' originally registered from UID "
+ << existing.ctx.uid << " but it is now being registered from UID "
+ << ctx.uid << ". Multiple instances installed?";
+ }
+
+ if (existing.ctx.sid != ctx.sid) {
+ LOG(WARNING) << "Service '" << name << "' originally registered from SID "
+ << existing.ctx.sid << " but it is now being registered from SID "
+ << ctx.sid << ". Multiple instances installed?";
+ }
+
+ LOG(INFO) << "Service '" << name << "' originally registered from PID "
+ << existing.ctx.debugPid << " but it is being registered again from PID "
+ << ctx.debugPid
+ << ". Bad state? Late death notification? Multiple instances installed?";
+ }
+
// 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
@@ -571,7 +596,7 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
- if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) {
+ if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")";
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
}
@@ -707,7 +732,7 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) {
+ if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
LOG(WARNING) << "Only a server can unregister itself (for " << name << ")";
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
}
@@ -754,7 +779,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/include/input/InputDevice.h b/include/input/InputDevice.h
index 415080d..0026e82 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/sensor.h>
+#include <ftl/flags.h>
#include <input/Input.h>
#include <input/KeyCharacterMap.h>
#include <unordered_map>
@@ -105,12 +106,18 @@
};
enum class InputDeviceLightType : int32_t {
- MONO = 0,
+ INPUT = 0,
PLAYER_ID = 1,
- RGB = 2,
- MULTI_COLOR = 3,
+ KEYBOARD_BACKLIGHT = 2,
- ftl_last = MULTI_COLOR
+ ftl_last = KEYBOARD_BACKLIGHT
+};
+
+enum class InputDeviceLightCapability : uint32_t {
+ /** Capability to change brightness of the light */
+ BRIGHTNESS = 0x00000001,
+ /** Capability to change color of the light */
+ RGB = 0x00000002,
};
struct InputDeviceSensorInfo {
@@ -171,14 +178,17 @@
struct InputDeviceLightInfo {
explicit InputDeviceLightInfo(std::string name, int32_t id, InputDeviceLightType type,
+ ftl::Flags<InputDeviceLightCapability> capabilityFlags,
int32_t ordinal)
- : name(name), id(id), type(type), ordinal(ordinal) {}
+ : name(name), id(id), type(type), capabilityFlags(capabilityFlags), ordinal(ordinal) {}
// Name string of the light.
std::string name;
// Light id
int32_t id;
// Type of the light.
InputDeviceLightType type;
+ // Light capabilities.
+ ftl::Flags<InputDeviceLightCapability> capabilityFlags;
// Ordinal of the light
int32_t ordinal;
};
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/Parcel.cpp b/libs/binder/Parcel.cpp
index 8887572..8333298 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2639,8 +2639,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 +2647,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 +2655,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/RpcState.cpp b/libs/binder/RpcState.cpp
index c0e36c4..c411f4f 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);
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/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/Android.bp b/libs/binder/ndk/Android.bp
index 33d28e6..8ae7537 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -182,4 +182,8 @@
name: "libbinder_ndk",
symbol_file: "libbinder_ndk.map.txt",
first_version: "29",
+ export_header_libs: [
+ "libbinder_ndk_headers",
+ "libbinder_ndk_helper_headers",
+ ],
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 21b0354..9a6d4df 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,9 @@
wp<RpcSession> weakSession = session;
session = nullptr;
- EXPECT_EQ(nullptr, weakSession.promote()) << "Leaked session";
+
+ EXPECT_EQ(nullptr, weakSession.promote())
+ << (debugBacktrace(host.getPid()), debugBacktrace(getpid()), "Leaked session");
}
}
};
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index fc0b1ee..72bd1fb 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -627,7 +627,6 @@
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
: mId(other.mId),
- mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
mAnimation(other.mAnimation),
mEarlyWakeupStart(other.mEarlyWakeupStart),
@@ -662,7 +661,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 +737,6 @@
// Parsing was successful. Update the object.
mId = transactionId;
- mForceSynchronous = forceSynchronous;
mTransactionNestCount = transactionNestCount;
mAnimation = animation;
mEarlyWakeupStart = earlyWakeupStart;
@@ -770,7 +767,6 @@
const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers();
parcel->writeUint64(mId);
- parcel->writeUint32(mForceSynchronous);
parcel->writeUint32(mTransactionNestCount);
parcel->writeBool(mAnimation);
parcel->writeBool(mEarlyWakeupStart);
@@ -890,7 +886,6 @@
mListenerCallbacks.clear();
mInputWindowCommands.clear();
mMayContainBuffer = false;
- mForceSynchronous = 0;
mTransactionNestCount = 0;
mAnimation = false;
mEarlyWakeupStart = false;
@@ -1003,27 +998,25 @@
Vector<DisplayState> displayStates;
uint32_t flags = 0;
- mForceSynchronous |= synchronous;
-
for (auto const& kv : mComposerStates){
composerStates.add(kv.second);
}
displayStates = std::move(mDisplayStates);
- if (mForceSynchronous) {
+ if (synchronous) {
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
@@ -2021,7 +2014,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) {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 963cc09..61d4714 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -403,7 +403,6 @@
uint64_t mId;
- uint32_t mForceSynchronous = 0;
uint32_t mTransactionNestCount = 0;
bool mAnimation = false;
bool mEarlyWakeupStart = false;
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index fbfecf6..3503a9e 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -61,6 +61,9 @@
// Android O
first_version: "26",
+ export_header_libs: [
+ "libnativewindow_ndk_headers",
+ ],
}
cc_library {
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 2237d2d..62cf255 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -12,7 +12,10 @@
name: "libETC1",
srcs: ["ETC1/etc1.cpp"],
host_supported: true,
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
target: {
android: {
@@ -37,6 +40,9 @@
symbol_file: "libEGL.map.txt",
first_version: "9",
unversioned_until: "current",
+ export_header_libs: [
+ "libEGL_headers",
+ ],
}
ndk_library {
@@ -44,6 +50,9 @@
symbol_file: "libGLESv1_CM.map.txt",
first_version: "9",
unversioned_until: "current",
+ export_header_libs: [
+ "libGLESv1_CM_headers",
+ ],
}
ndk_library {
@@ -51,6 +60,9 @@
symbol_file: "libGLESv2.map.txt",
first_version: "9",
unversioned_until: "current",
+ export_header_libs: [
+ "libGLESv2_headers",
+ ],
}
ndk_library {
@@ -58,6 +70,9 @@
symbol_file: "libGLESv3.map.txt",
first_version: "18",
unversioned_until: "current",
+ export_header_libs: [
+ "libGLESv3_headers",
+ ],
}
cc_defaults {
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/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 54d0e02..0972e22 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -31,206 +31,6 @@
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) {}
-
-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..1f37774
--- /dev/null
+++ b/services/inputflinger/NotifyArgs.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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) {}
+
+} // 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..399153c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -544,17 +544,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 +557,6 @@
SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
mKeyRepeatState.lastKeyEntry = nullptr;
-
policy->getDispatcherConfiguration(&mConfig);
}
@@ -1435,7 +1429,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 +1446,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;
@@ -5012,15 +5005,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 +5028,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 +5470,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 +6372,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..630d21a 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){};
@@ -384,7 +387,7 @@
bool hasResponsiveConnectionLocked(android::gui::WindowInfoHandle& windowHandle) 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..8647bcb 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -21,200 +21,10 @@
#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>;
-
/*
* 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..611b1aa
--- /dev/null
+++ b/services/inputflinger/include/NotifyArgs.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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>;
+
+} // 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 c9d21dc..ca7e426 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -76,6 +76,8 @@
static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
+static constexpr size_t EVENT_BUFFER_SIZE = 256;
+
// Mapping for input battery class node IDs lookup.
// https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
static const std::unordered_map<std::string, InputBatteryClass> BATTERY_CLASSES =
@@ -117,7 +119,8 @@
{"brightness", InputLightClass::BRIGHTNESS},
{"multi_index", InputLightClass::MULTI_INDEX},
{"multi_intensity", InputLightClass::MULTI_INTENSITY},
- {"max_brightness", InputLightClass::MAX_BRIGHTNESS}};
+ {"max_brightness", InputLightClass::MAX_BRIGHTNESS},
+ {"kbd_backlight", InputLightClass::KEYBOARD_BACKLIGHT}};
// Mapping for input multicolor led class node names.
// https://www.kernel.org/doc/html/latest/leds/leds-class-multicolor.html
@@ -365,15 +368,26 @@
info.path = nodePath;
info.name = nodePath.filename();
info.maxBrightness = std::nullopt;
- size_t nameStart = info.name.rfind(":");
- if (nameStart != std::string::npos) {
- // Trim the name to color name
- info.name = info.name.substr(nameStart + 1);
- // Set InputLightClass flag for colors
- const auto it = LIGHT_CLASSES.find(info.name);
- if (it != LIGHT_CLASSES.end()) {
- info.flags |= it->second;
+
+ // Light name should follow the naming pattern <name>:<color>:<function>
+ // Refer kernel docs /leds/leds-class.html for valid supported LED names.
+ std::regex indexPattern("([a-zA-Z0-9_.:]*:)?([a-zA-Z0-9_.]*):([a-zA-Z0-9_.]*)");
+ std::smatch results;
+
+ if (std::regex_match(info.name, results, indexPattern)) {
+ // regex_match will return full match at index 0 and <name> at index 1. For RawLightInfo
+ // we only care about sections <color> and <function> which will be at index 2 and 3.
+ for (int i = 2; i <= 3; i++) {
+ const auto it = LIGHT_CLASSES.find(results.str(i));
+ if (it != LIGHT_CLASSES.end()) {
+ info.flags |= it->second;
+ }
}
+
+ // Set name of the raw light to <function> which represents playerIDs for LEDs that
+ // turn on/off based on the current player ID (Refer to PeripheralController.cpp for
+ // player ID logic)
+ info.name = results.str(3);
}
// Scan the path for all the files
// Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
@@ -1404,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) {
@@ -1621,15 +1646,12 @@
return std::nullopt;
}
-size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
- ALOG_ASSERT(bufferSize >= 1);
-
+std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) {
std::scoped_lock _l(mLock);
- struct input_event readBuffer[bufferSize];
+ std::array<input_event, EVENT_BUFFER_SIZE> readBuffer;
- RawEvent* event = buffer;
- size_t capacity = bufferSize;
+ std::vector<RawEvent> events;
bool awoken = false;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -1649,15 +1671,17 @@
for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {
std::unique_ptr<Device> device = std::move(*it);
ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
- event->when = now;
- event->deviceId = (device->id == mBuiltInKeyboardId)
+ const int32_t deviceId = (device->id == mBuiltInKeyboardId)
? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
: device->id;
- event->type = DEVICE_REMOVED;
- event += 1;
+ events.push_back({
+ .when = now,
+ .deviceId = deviceId,
+ .type = DEVICE_REMOVED,
+ });
it = mClosingDevices.erase(it);
mNeedToSendFinishedDeviceScan = true;
- if (--capacity == 0) {
+ if (events.size() == EVENT_BUFFER_SIZE) {
break;
}
}
@@ -1672,10 +1696,12 @@
std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());
mOpeningDevices.pop_back();
ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
- event->when = now;
- event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
- event->type = DEVICE_ADDED;
- event += 1;
+ const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+ events.push_back({
+ .when = now,
+ .deviceId = deviceId,
+ .type = DEVICE_ADDED,
+ });
// Try to find a matching video device by comparing device names
for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();
@@ -1693,17 +1719,18 @@
ALOGW("Device id %d exists, replaced.", device->id);
}
mNeedToSendFinishedDeviceScan = true;
- if (--capacity == 0) {
+ if (events.size() == EVENT_BUFFER_SIZE) {
break;
}
}
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
- event->when = now;
- event->type = FINISHED_DEVICE_SCAN;
- event += 1;
- if (--capacity == 0) {
+ events.push_back({
+ .when = now,
+ .type = FINISHED_DEVICE_SCAN,
+ });
+ if (events.size() == EVENT_BUFFER_SIZE) {
break;
}
}
@@ -1767,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) {
@@ -1782,21 +1810,21 @@
} else if ((readSize % sizeof(struct input_event)) != 0) {
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
- int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+ const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
- size_t count = size_t(readSize) / sizeof(struct input_event);
+ const size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
- event->when = processEventTimestamp(iev);
- event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);
- event->deviceId = deviceId;
- event->type = iev.type;
- event->code = iev.code;
- event->value = iev.value;
- event += 1;
- capacity -= 1;
+ events.push_back({
+ .when = processEventTimestamp(iev),
+ .readTime = systemTime(SYSTEM_TIME_MONOTONIC),
+ .deviceId = deviceId,
+ .type = iev.type,
+ .code = iev.code,
+ .value = iev.value,
+ });
}
- if (capacity == 0) {
+ 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;
@@ -1832,7 +1860,7 @@
}
// Return now if we have collected any events or if we were explicitly awoken.
- if (event != buffer || awoken) {
+ if (!events.empty() || awoken) {
break;
}
@@ -1878,7 +1906,7 @@
}
// All done, return the number of events we read.
- return event - buffer;
+ return events;
}
std::vector<TouchVideoFrame> EventHub::getVideoFrames(int32_t deviceId) {
@@ -2633,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..6b9b9f1 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -234,6 +234,10 @@
}
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);
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 4c38ce8..8650876 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -120,14 +120,14 @@
}
} // release lock
- size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
+ std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);
{ // acquire lock
std::scoped_lock _l(mLock);
mReaderIsAliveCondition.notify_all();
- if (count) {
- processEventsLocked(mEventBuffer, count);
+ if (!events.empty()) {
+ processEventsLocked(events.data(), events.size());
}
if (mNextTimeout != LLONG_MAX) {
diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp
index eaf5b51..cedbacb 100644
--- a/services/inputflinger/reader/controller/PeripheralController.cpp
+++ b/services/inputflinger/reader/controller/PeripheralController.cpp
@@ -16,6 +16,7 @@
#include <locale>
#include <regex>
+#include <set>
#include <ftl/enum.h>
@@ -70,7 +71,7 @@
// If the light node doesn't have max brightness, use the default max brightness.
int rawMaxBrightness = rawInfoOpt->maxBrightness.value_or(MAX_BRIGHTNESS);
- float ratio = MAX_BRIGHTNESS / rawMaxBrightness;
+ float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
// Scale the returned brightness in [0, rawMaxBrightness] to [0, 255]
if (rawMaxBrightness != MAX_BRIGHTNESS) {
brightness = brightness * ratio;
@@ -89,7 +90,7 @@
}
// If the light node doesn't have max brightness, use the default max brightness.
int rawMaxBrightness = rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS);
- float ratio = MAX_BRIGHTNESS / rawMaxBrightness;
+ float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
// Scale the requested brightness in [0, 255] to [0, rawMaxBrightness]
if (rawMaxBrightness != MAX_BRIGHTNESS) {
brightness = ceil(brightness / ratio);
@@ -271,7 +272,8 @@
for (const auto& [lightId, light] : mLights) {
// Input device light doesn't support ordinal, always pass 1.
- InputDeviceLightInfo lightInfo(light->name, light->id, light->type, 1 /* ordinal */);
+ InputDeviceLightInfo lightInfo(light->name, light->id, light->type, light->capabilityFlags,
+ 1 /* ordinal */);
deviceInfo->addLightInfo(lightInfo);
}
}
@@ -284,6 +286,8 @@
dump += StringPrintf(INDENT4 "Id: %d", lightId);
dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str());
dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str());
+ dump += StringPrintf(INDENT4 "Capability flags: %s",
+ light->capabilityFlags.string().c_str());
light->dump(dump);
}
}
@@ -363,6 +367,8 @@
std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
// Map from player Id to raw light Id
std::unordered_map<int32_t, int32_t> playerIdLightIds;
+ // Set of Keyboard backlights
+ std::set<int32_t> keyboardBacklightIds;
// Check raw lights
const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
@@ -391,6 +397,10 @@
}
}
}
+ // Check if this is a Keyboard backlight
+ if (rawInfo->flags.test(InputLightClass::KEYBOARD_BACKLIGHT)) {
+ keyboardBacklightIds.insert(rawId);
+ }
// Check if this is an LED of RGB light
if (rawInfo->flags.test(InputLightClass::RED)) {
hasRedLed = true;
@@ -431,8 +441,21 @@
ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED),
rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
}
+ bool isKeyboardBacklight = keyboardBacklightIds.find(rawRgbIds.at(LightColor::RED)) !=
+ keyboardBacklightIds.end() &&
+ keyboardBacklightIds.find(rawRgbIds.at(LightColor::GREEN)) !=
+ keyboardBacklightIds.end() &&
+ keyboardBacklightIds.find(rawRgbIds.at(LightColor::BLUE)) !=
+ keyboardBacklightIds.end() &&
+ (!rawGlobalId.has_value() ||
+ keyboardBacklightIds.find(rawGlobalId.value()) != keyboardBacklightIds.end());
+
std::unique_ptr<Light> light =
- std::make_unique<RgbLight>(getDeviceContext(), ++mNextId, rawRgbIds, rawGlobalId);
+ std::make_unique<RgbLight>(getDeviceContext(), ++mNextId,
+ isKeyboardBacklight
+ ? InputDeviceLightType::KEYBOARD_BACKLIGHT
+ : InputDeviceLightType::INPUT,
+ rawRgbIds, rawGlobalId);
mLights.insert_or_assign(light->id, std::move(light));
// Remove from raw light info as they've been composed a RBG light.
rawInfos.erase(rawRgbIds.at(LightColor::RED));
@@ -445,6 +468,10 @@
// Check the rest of raw light infos
for (const auto& [rawId, rawInfo] : rawInfos) {
+ InputDeviceLightType type = keyboardBacklightIds.find(rawId) != keyboardBacklightIds.end()
+ ? InputDeviceLightType::KEYBOARD_BACKLIGHT
+ : InputDeviceLightType::INPUT;
+
// If the node is multi-color led, construct a MULTI_COLOR light
if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) &&
rawInfo.flags.test(InputLightClass::MULTI_INTENSITY)) {
@@ -453,7 +480,7 @@
}
std::unique_ptr<Light> light =
std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name, ++mNextId,
- rawInfo.id);
+ type, rawInfo.id);
mLights.insert_or_assign(light->id, std::move(light));
continue;
}
@@ -462,7 +489,7 @@
ALOGD("Mono light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
}
std::unique_ptr<Light> light = std::make_unique<MonoLight>(getDeviceContext(), rawInfo.name,
- ++mNextId, rawInfo.id);
+ ++mNextId, type, rawInfo.id);
mLights.insert_or_assign(light->id, std::move(light));
}
diff --git a/services/inputflinger/reader/controller/PeripheralController.h b/services/inputflinger/reader/controller/PeripheralController.h
index 25cf435..8ac42c3 100644
--- a/services/inputflinger/reader/controller/PeripheralController.h
+++ b/services/inputflinger/reader/controller/PeripheralController.h
@@ -67,6 +67,7 @@
std::string name;
int32_t id;
InputDeviceLightType type;
+ ftl::Flags<InputDeviceLightCapability> capabilityFlags;
virtual bool setLightColor(int32_t color) { return false; }
virtual std::optional<int32_t> getLightColor() { return std::nullopt; }
@@ -81,8 +82,10 @@
struct MonoLight : public Light {
explicit MonoLight(InputDeviceContext& context, const std::string& name, int32_t id,
- int32_t rawId)
- : Light(context, name, id, InputDeviceLightType::MONO), rawId(rawId) {}
+ InputDeviceLightType type, int32_t rawId)
+ : Light(context, name, id, type), rawId(rawId) {
+ capabilityFlags |= InputDeviceLightCapability::BRIGHTNESS;
+ }
int32_t rawId;
bool setLightColor(int32_t color) override;
@@ -91,15 +94,15 @@
};
struct RgbLight : public Light {
- explicit RgbLight(InputDeviceContext& context, int32_t id,
+ explicit RgbLight(InputDeviceContext& context, int32_t id, InputDeviceLightType type,
const std::unordered_map<LightColor, int32_t>& rawRgbIds,
std::optional<int32_t> rawGlobalId)
- : Light(context, "RGB", id, InputDeviceLightType::RGB),
- rawRgbIds(rawRgbIds),
- rawGlobalId(rawGlobalId) {
+ : Light(context, "RGB", id, type), rawRgbIds(rawRgbIds), rawGlobalId(rawGlobalId) {
brightness = rawGlobalId.has_value()
? getRawLightBrightness(rawGlobalId.value()).value_or(MAX_BRIGHTNESS)
: MAX_BRIGHTNESS;
+ capabilityFlags |= InputDeviceLightCapability::BRIGHTNESS;
+ capabilityFlags |= InputDeviceLightCapability::RGB;
}
// Map from color to raw light id.
std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
@@ -114,8 +117,11 @@
struct MultiColorLight : public Light {
explicit MultiColorLight(InputDeviceContext& context, const std::string& name, int32_t id,
- int32_t rawId)
- : Light(context, name, id, InputDeviceLightType::MULTI_COLOR), rawId(rawId) {}
+ InputDeviceLightType type, int32_t rawId)
+ : Light(context, name, id, type), rawId(rawId) {
+ capabilityFlags |= InputDeviceLightCapability::BRIGHTNESS;
+ capabilityFlags |= InputDeviceLightCapability::RGB;
+ }
int32_t rawId;
bool setLightColor(int32_t color) override;
@@ -131,7 +137,7 @@
// Map from player Id to raw light Id
std::unordered_map<int32_t, int32_t> rawLightIds;
- bool setLightPlayerId(int32_t palyerId) override;
+ bool setLightPlayerId(int32_t playerId) override;
std::optional<int32_t> getLightPlayerId() override;
void dump(std::string& dump) override;
};
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 5cf2214..6933ec7 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -174,6 +174,8 @@
MULTI_INTENSITY = 0x00000040,
/* The input light has max brightness node. */
MAX_BRIGHTNESS = 0x00000080,
+ /* The input light has kbd_backlight name */
+ KEYBOARD_BACKLIGHT = 0x00000100,
};
enum class InputBatteryClass : uint32_t {
@@ -193,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. */
@@ -201,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;
};
/*
@@ -280,7 +288,7 @@
*
* Returns the number of events obtained, or 0 if the timeout expired.
*/
- virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;
+ virtual std::vector<RawEvent> getEvents(int timeoutMillis) = 0;
virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) = 0;
virtual base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(
int32_t deviceId, int32_t absCode) const = 0;
@@ -498,7 +506,7 @@
bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
uint8_t* outFlags) const override final;
- size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override final;
+ std::vector<RawEvent> getEvents(int timeoutMillis) override final;
std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override final;
bool hasScanCode(int32_t deviceId, int32_t scanCode) const override final;
@@ -549,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 {
@@ -582,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/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index fbce87f..012d43f 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -170,10 +170,6 @@
InputReaderConfiguration mConfig GUARDED_BY(mLock);
- // The event queue.
- static const int EVENT_BUFFER_SIZE = 256;
- RawEvent mEventBuffer[EVENT_BUFFER_SIZE] GUARDED_BY(mLock);
-
// An input device can represent a collection of EventHub devices. This map provides a way
// to lookup the input device instance from the EventHub device id.
std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index 6ef6e44..9380c71 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -99,8 +99,6 @@
};
std::vector<RawEvent> EventHubTest::getEvents(std::optional<size_t> expectedEvents) {
- static constexpr size_t EVENT_BUFFER_SIZE = 256;
- std::array<RawEvent, EVENT_BUFFER_SIZE> eventBuffer;
std::vector<RawEvent> events;
while (true) {
@@ -108,12 +106,12 @@
if (expectedEvents) {
timeout = 2s;
}
- const size_t count =
- mEventHub->getEvents(timeout.count(), eventBuffer.data(), eventBuffer.size());
- if (count == 0) {
+
+ std::vector<RawEvent> newEvents = mEventHub->getEvents(timeout.count());
+ if (newEvents.empty()) {
break;
}
- events.insert(events.end(), eventBuffer.begin(), eventBuffer.begin() + count);
+ events.insert(events.end(), newEvents.begin(), newEvents.end());
if (expectedEvents && events.size() >= *expectedEvents) {
break;
}
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
index 22ae894..ca548be 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -33,8 +33,6 @@
#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>
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 097659b..78ea692 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -826,15 +826,14 @@
mExcludedDevices = devices;
}
- size_t getEvents(int, RawEvent* buffer, size_t bufferSize) override {
+ std::vector<RawEvent> getEvents(int) override {
std::scoped_lock lock(mLock);
- const size_t filledSize = std::min(mEvents.size(), bufferSize);
- std::copy(mEvents.begin(), mEvents.begin() + filledSize, buffer);
+ std::vector<RawEvent> buffer;
+ std::swap(buffer, mEvents);
- mEvents.erase(mEvents.begin(), mEvents.begin() + filledSize);
mEventsCondition.notify_all();
- return filledSize;
+ return buffer;
}
std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override {
@@ -2972,6 +2971,21 @@
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 {
@@ -10107,7 +10121,7 @@
TEST_F(LightControllerTest, MonoLight) {
RawLightInfo infoMono = {.id = 1,
- .name = "Mono",
+ .name = "mono_light",
.maxBrightness = 255,
.flags = InputLightClass::BRIGHTNESS,
.path = ""};
@@ -10118,7 +10132,29 @@
controller.populateDeviceInfo(&info);
std::vector<InputDeviceLightInfo> lights = info.getLights();
ASSERT_EQ(1U, lights.size());
- ASSERT_EQ(InputDeviceLightType::MONO, lights[0].type);
+ ASSERT_EQ(InputDeviceLightType::INPUT, lights[0].type);
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS));
+
+ ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_BRIGHTNESS));
+ ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_BRIGHTNESS);
+}
+
+TEST_F(LightControllerTest, MonoKeyboardBacklight) {
+ RawLightInfo infoMono = {.id = 1,
+ .name = "mono_keyboard_backlight",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS |
+ InputLightClass::KEYBOARD_BACKLIGHT,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono));
+
+ PeripheralController& controller = addControllerAndConfigure<PeripheralController>();
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ std::vector<InputDeviceLightInfo> lights = info.getLights();
+ ASSERT_EQ(1U, lights.size());
+ ASSERT_EQ(InputDeviceLightType::KEYBOARD_BACKLIGHT, lights[0].type);
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS));
ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_BRIGHTNESS));
ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_BRIGHTNESS);
@@ -10149,7 +10185,85 @@
controller.populateDeviceInfo(&info);
std::vector<InputDeviceLightInfo> lights = info.getLights();
ASSERT_EQ(1U, lights.size());
- ASSERT_EQ(InputDeviceLightType::RGB, lights[0].type);
+ ASSERT_EQ(InputDeviceLightType::INPUT, lights[0].type);
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS));
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB));
+
+ ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR));
+ ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR);
+}
+
+TEST_F(LightControllerTest, CorrectRGBKeyboardBacklight) {
+ RawLightInfo infoRed = {.id = 1,
+ .name = "red_keyboard_backlight",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::RED |
+ InputLightClass::KEYBOARD_BACKLIGHT,
+ .path = ""};
+ RawLightInfo infoGreen = {.id = 2,
+ .name = "green_keyboard_backlight",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::GREEN |
+ InputLightClass::KEYBOARD_BACKLIGHT,
+ .path = ""};
+ RawLightInfo infoBlue = {.id = 3,
+ .name = "blue_keyboard_backlight",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::BLUE |
+ InputLightClass::KEYBOARD_BACKLIGHT,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed));
+ mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen));
+ mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue));
+
+ PeripheralController& controller = addControllerAndConfigure<PeripheralController>();
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ std::vector<InputDeviceLightInfo> lights = info.getLights();
+ ASSERT_EQ(1U, lights.size());
+ ASSERT_EQ(InputDeviceLightType::KEYBOARD_BACKLIGHT, lights[0].type);
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS));
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB));
+
+ ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR));
+ ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR);
+}
+
+TEST_F(LightControllerTest, IncorrectRGBKeyboardBacklight) {
+ RawLightInfo infoRed = {.id = 1,
+ .name = "red",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::RED,
+ .path = ""};
+ RawLightInfo infoGreen = {.id = 2,
+ .name = "green",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::GREEN,
+ .path = ""};
+ RawLightInfo infoBlue = {.id = 3,
+ .name = "blue",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::BLUE,
+ .path = ""};
+ RawLightInfo infoGlobal = {.id = 3,
+ .name = "global_keyboard_backlight",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS | InputLightClass::GLOBAL |
+ InputLightClass::KEYBOARD_BACKLIGHT,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed));
+ mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen));
+ mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue));
+ mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoGlobal));
+
+ PeripheralController& controller = addControllerAndConfigure<PeripheralController>();
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ std::vector<InputDeviceLightInfo> lights = info.getLights();
+ ASSERT_EQ(1U, lights.size());
+ ASSERT_EQ(InputDeviceLightType::INPUT, lights[0].type);
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS));
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB));
ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR));
ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR);
@@ -10157,7 +10271,7 @@
TEST_F(LightControllerTest, MultiColorRGBLight) {
RawLightInfo infoColor = {.id = 1,
- .name = "red",
+ .name = "multi_color",
.maxBrightness = 255,
.flags = InputLightClass::BRIGHTNESS |
InputLightClass::MULTI_INTENSITY |
@@ -10171,7 +10285,34 @@
controller.populateDeviceInfo(&info);
std::vector<InputDeviceLightInfo> lights = info.getLights();
ASSERT_EQ(1U, lights.size());
- ASSERT_EQ(InputDeviceLightType::MULTI_COLOR, lights[0].type);
+ ASSERT_EQ(InputDeviceLightType::INPUT, lights[0].type);
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS));
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB));
+
+ ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR));
+ ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR);
+}
+
+TEST_F(LightControllerTest, MultiColorRGBKeyboardBacklight) {
+ RawLightInfo infoColor = {.id = 1,
+ .name = "multi_color_keyboard_backlight",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS |
+ InputLightClass::MULTI_INTENSITY |
+ InputLightClass::MULTI_INDEX |
+ InputLightClass::KEYBOARD_BACKLIGHT,
+ .path = ""};
+
+ mFakeEventHub->addRawLightInfo(infoColor.id, std::move(infoColor));
+
+ PeripheralController& controller = addControllerAndConfigure<PeripheralController>();
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ std::vector<InputDeviceLightInfo> lights = info.getLights();
+ ASSERT_EQ(1U, lights.size());
+ ASSERT_EQ(InputDeviceLightType::KEYBOARD_BACKLIGHT, lights[0].type);
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS));
+ ASSERT_TRUE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB));
ASSERT_TRUE(controller.setLightColor(lights[0].id, LIGHT_COLOR));
ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_COLOR);
@@ -10209,6 +10350,8 @@
std::vector<InputDeviceLightInfo> lights = info.getLights();
ASSERT_EQ(1U, lights.size());
ASSERT_EQ(InputDeviceLightType::PLAYER_ID, lights[0].type);
+ ASSERT_FALSE(lights[0].capabilityFlags.test(InputDeviceLightCapability::BRIGHTNESS));
+ ASSERT_FALSE(lights[0].capabilityFlags.test(InputDeviceLightCapability::RGB));
ASSERT_FALSE(controller.setLightColor(lights[0].id, LIGHT_COLOR));
ASSERT_TRUE(controller.setLightPlayerId(lights[0].id, LIGHT_PLAYER_ID));
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/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index f5bd297..a9f5a3a 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -169,7 +169,6 @@
std::shared_ptr<FuzzEventHub> fuzzEventHub = std::make_shared<FuzzEventHub>(fdp);
std::unique_ptr<FuzzInputReader> reader =
std::make_unique<FuzzInputReader>(fuzzEventHub, fuzzPolicy, fuzzListener);
- fuzzEventHub->addEvents(fdp);
size_t patternCount = fdp->ConsumeIntegralInRange<size_t>(1, 260);
VibrationSequence pattern(patternCount);
for (size_t i = 0; i < patternCount; ++i) {
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 53a7b16..03c2266 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -114,30 +114,12 @@
InputDeviceIdentifier mIdentifier;
std::vector<TouchVideoFrame> mVideoFrames;
PropertyMap mFuzzConfig;
- size_t mCount = 0;
- std::array<RawEvent, kMaxSize> mBuf;
std::shared_ptr<FuzzedDataProvider> mFdp;
public:
FuzzEventHub(std::shared_ptr<FuzzedDataProvider> fdp) : mFdp(std::move(fdp)) {}
~FuzzEventHub() {}
void addProperty(std::string key, std::string value) { mFuzzConfig.addProperty(key, value); }
- void addEvents(std::shared_ptr<FuzzedDataProvider> fdp) {
- mCount = fdp->ConsumeIntegralInRange<size_t>(0, kMaxSize);
-
- for (size_t i = 0; i < mCount; ++i) {
- int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
- : fdp->ConsumeIntegral<int32_t>();
- int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
- : fdp->ConsumeIntegral<int32_t>();
- mBuf[i] = {fdp->ConsumeIntegral<nsecs_t>(),
- fdp->ConsumeIntegral<nsecs_t>(),
- fdp->ConsumeIntegral<int32_t>(),
- type,
- code,
- fdp->ConsumeIntegral<int32_t>()};
- }
- }
ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
return ftl::Flags<InputDeviceClass>(mFdp->ConsumeIntegral<uint32_t>());
@@ -168,10 +150,24 @@
return mFdp->ConsumeIntegral<status_t>();
}
void setExcludedDevices(const std::vector<std::string>& devices) override {}
- size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override {
- for (size_t i = 0; i < mCount; ++i) buffer[i] = mBuf[i];
-
- return mCount;
+ std::vector<RawEvent> getEvents(int timeoutMillis) override {
+ std::vector<RawEvent> events;
+ const size_t count = mFdp->ConsumeIntegralInRange<size_t>(0, kMaxSize);
+ for (size_t i = 0; i < count; ++i) {
+ int32_t type = mFdp->ConsumeBool() ? mFdp->PickValueInArray(kValidTypes)
+ : mFdp->ConsumeIntegral<int32_t>();
+ int32_t code = mFdp->ConsumeBool() ? mFdp->PickValueInArray(kValidCodes)
+ : mFdp->ConsumeIntegral<int32_t>();
+ events.push_back({
+ .when = mFdp->ConsumeIntegral<nsecs_t>(),
+ .readTime = mFdp->ConsumeIntegral<nsecs_t>(),
+ .deviceId = mFdp->ConsumeIntegral<int32_t>(),
+ .type = type,
+ .code = code,
+ .value = mFdp->ConsumeIntegral<int32_t>(),
+ });
+ }
+ return events;
}
std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override { return mVideoFrames; }
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/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h
new file mode 100644
index 0000000..ee8000a
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <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 d7704a8..9102139 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/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a25296c..f8115eb 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -238,16 +238,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;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 0f52aff..510df81 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -233,9 +233,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,
@@ -273,8 +271,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;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 486eaf8..96399e2 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -70,7 +70,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 15d5041..0a4ad97 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 92a8f30..6c43d8b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -160,8 +160,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;
@@ -214,7 +215,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;
@@ -343,8 +344,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;
@@ -387,7 +389,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;
@@ -456,7 +458,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;
@@ -466,8 +471,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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 13437a4..410e438 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -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(),
@@ -4241,6 +4246,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..4ff86e5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -166,6 +166,8 @@
ui::Transform transform;
Rect bufferSize;
std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ LayerMetadata layerMetadata;
+ LayerMetadata relativeLayerMetadata;
};
using FrameRate = scheduler::LayerInfo::FrameRate;
@@ -611,6 +613,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);
@@ -901,6 +909,9 @@
// 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;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e27c713..7d3fc98 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1893,17 +1893,12 @@
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 auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId);
const bool isActiveDisplay =
displayId && getPhysicalDisplayTokenLocked(*displayId) == mActiveDisplayToken;
if (!isActiveDisplay) {
@@ -2211,6 +2206,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) {
@@ -4445,7 +4447,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)) {
@@ -7240,6 +7245,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() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3c92d56..85d11ba 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -608,7 +608,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;
@@ -699,6 +699,7 @@
bool latchBuffers();
void updateLayerGeometry();
+ void updateLayerMetadataSnapshot();
void updateInputFlinger();
void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
@@ -1176,6 +1177,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;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index dec14d0..4469df0 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -109,6 +109,7 @@
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
"SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
+ "SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp",
"SchedulerTest.cpp",
"SetFrameRateTest.cpp",
"RefreshRateConfigsTest.cpp",
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/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2c9c451..13389a1 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -477,6 +477,8 @@
return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
}
+ void updateLayerMetadataSnapshot() { mFlinger->updateLayerMetadataSnapshot(); }
+
/* ------------------------------------------------------------------------
* Read-only access to private data to assert post-conditions.
*/
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 5719b5c..a87f82f 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -27,6 +27,9 @@
symbol_file: "libvulkan.map.txt",
first_version: "24",
unversioned_until: "current",
+ export_header_libs: [
+ "ndk_vulkan_headers",
+ ],
}
cc_library_shared {