Merge "Override buffer always sets blend mode and plane alpha" into sc-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 922367f..8bcb1e5 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,6 +5,7 @@
# Only turn on clang-format check for the following subfolders.
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
cmds/idlcli/
+ cmds/servicemanager/
include/input/
include/powermanager/
libs/binder/fuzzer/
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index ee75957..c5e3587 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -497,6 +497,35 @@
int8_t compatibility, int8_t changeFrameRateStrategy)
__INTRODUCED_IN(31);
+/**
+ * Indicate whether to enable backpressure for buffer submission to a given SurfaceControl.
+ *
+ * By default backpressure is disabled, which means submitting a buffer prior to receiving
+ * a callback for the previous buffer could lead to that buffer being "dropped". In cases
+ * where you are selecting for latency, this may be a desirable behavior! We had a new buffer
+ * ready, why shouldn't we show it?
+ *
+ * When back pressure is enabled, each buffer will be required to be presented
+ * before it is released and the callback delivered
+ * (absent the whole SurfaceControl being removed).
+ *
+ * Most apps are likely to have some sort of backpressure internally, e.g. you are
+ * waiting on the callback from frame N-2 before starting frame N. In high refresh
+ * rate scenarios there may not be much time between SurfaceFlinger completing frame
+ * N-1 (and therefore releasing buffer N-2) and beginning frame N. This means
+ * your app may not have enough time to respond in the callback. Using this flag
+ * and pushing buffers earlier for server side queuing will be advantageous
+ * in such cases.
+ *
+ * \param transaction The transaction in which to make the change.
+ * \param surface_control The ASurfaceControl on which to control buffer backpressure behavior.
+ * \param enableBackPressure Whether to enable back pressure.
+ */
+void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control,
+ bool enableBackPressure)
+ __INTRODUCED_IN(31);
+
__END_DECLS
#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 2deb99d..712adfa 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -177,6 +177,14 @@
int32_t ordinal;
};
+struct InputDeviceBatteryInfo {
+ explicit InputDeviceBatteryInfo(std::string name, int32_t id) : name(name), id(id) {}
+ // Name string of the battery.
+ std::string name;
+ // Battery id
+ int32_t id;
+};
+
/*
* Describes the characteristics and capabilities of an input device.
*/
@@ -219,6 +227,7 @@
float min, float max, float flat, float fuzz, float resolution);
void addMotionRange(const MotionRange& range);
void addSensorInfo(const InputDeviceSensorInfo& info);
+ void addBatteryInfo(const InputDeviceBatteryInfo& info);
void addLightInfo(const InputDeviceLightInfo& info);
inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
@@ -276,6 +285,8 @@
std::unordered_map<InputDeviceSensorType, InputDeviceSensorInfo> mSensors;
/* Map from light ID to light info */
std::unordered_map<int32_t, InputDeviceLightInfo> mLights;
+ /* Map from battery ID to battery info */
+ std::unordered_map<int32_t, InputDeviceBatteryInfo> mBatteries;
};
/* Types of input device configuration files. */
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b0e8c7c..ea6d000 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -65,13 +65,10 @@
"IActivityManager.cpp",
"IAppOpsCallback.cpp",
"IAppOpsService.cpp",
- "IMediaResourceMonitor.cpp",
"IPermissionController.cpp",
- "IProcessInfoService.cpp",
"IUidObserver.cpp",
"PermissionCache.cpp",
"PermissionController.cpp",
- "ProcessInfoService.cpp",
"IpPrefix.cpp",
":activity_manager_procstate_aidl",
]
@@ -283,3 +280,17 @@
"libutils",
],
}
+
+cc_library {
+ name: "libprocessinfoservice_aidl",
+ srcs: [
+ "IProcessInfoService.cpp",
+ "ProcessInfoService.cpp",
+ ],
+ export_include_dirs: ["include_processinfo"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "liblog",
+ ],
+}
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 825a821..53b36ff 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -194,10 +194,13 @@
const String16& BpBinder::getInterfaceDescriptor() const
{
if (isDescriptorCached() == false) {
- Parcel send, reply;
+ sp<BpBinder> thiz = const_cast<BpBinder*>(this);
+
+ Parcel data;
+ data.markForBinder(thiz);
+ Parcel reply;
// do the IPC without a lock held.
- status_t err = const_cast<BpBinder*>(this)->transact(
- INTERFACE_TRANSACTION, send, &reply);
+ status_t err = thiz->transact(INTERFACE_TRANSACTION, data, &reply);
if (err == NO_ERROR) {
String16 res(reply.readString16());
Mutex::Autolock _l(mLock);
diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp
deleted file mode 100644
index f5fa817..0000000
--- a/libs/binder/IMediaResourceMonitor.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <binder/IMediaResourceMonitor.h>
-#include <binder/Parcel.h>
-#include <utils/Errors.h>
-#include <sys/types.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BpMediaResourceMonitor : public BpInterface<IMediaResourceMonitor> {
-public:
- explicit BpMediaResourceMonitor(const sp<IBinder>& impl)
- : BpInterface<IMediaResourceMonitor>(impl) {}
-
- virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaResourceMonitor::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeInt32(type);
- remote()->transact(NOTIFY_RESOURCE_GRANTED, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMonitor")
-
-// ----------------------------------------------------------------------
-
-// NOLINTNEXTLINE(google-default-arguments)
-status_t BnMediaResourceMonitor::onTransact( uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags) {
- switch(code) {
- case NOTIFY_RESOURCE_GRANTED: {
- CHECK_INTERFACE(IMediaResourceMonitor, data, reply);
- int32_t pid = data.readInt32();
- const int32_t type = data.readInt32();
- notifyResourceGranted(/*in*/ pid, /*in*/ type);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------
-
-} // namespace android
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
index 570edb9..d26754e 100644
--- a/libs/binder/IProcessInfoService.cpp
+++ b/libs/binder/IProcessInfoService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <binder/IProcessInfoService.h>
+#include <processinfo/IProcessInfoService.h>
#include <binder/Parcel.h>
#include <utils/Errors.h>
#include <sys/types.h>
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
index f75141e..0fb954a 100644
--- a/libs/binder/ProcessInfoService.cpp
+++ b/libs/binder/ProcessInfoService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <binder/ProcessInfoService.h>
+#include <processinfo/ProcessInfoService.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index 83a1618..dab3246 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -20,6 +20,7 @@
#include <binder/Parcel.h>
#include <binder/Stability.h>
+#include <utils/String8.h>
#include "RpcState.h"
#include "RpcWireFormat.h"
@@ -29,14 +30,20 @@
#include <sys/un.h>
#include <unistd.h>
-#if defined(__GLIBC__)
+#ifdef __GLIBC__
extern "C" pid_t gettid();
#endif
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#endif
+
namespace android {
using base::unique_fd;
+RpcConnection::SocketAddress::~SocketAddress() {}
+
RpcConnection::RpcConnection() {
LOG_RPC_DETAIL("RpcConnection created %p", this);
@@ -50,65 +57,68 @@
return new RpcConnection;
}
+class UnixSocketAddress : public RpcConnection::SocketAddress {
+public:
+ explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
+ unsigned int pathLen = strlen(path) + 1;
+ LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "%u %s", pathLen, path);
+ memcpy(mAddr.sun_path, path, pathLen);
+ }
+ virtual ~UnixSocketAddress() {}
+ std::string toString() const override {
+ return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
+ mAddr.sun_path)
+ .c_str();
+ }
+ const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+ size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+ sockaddr_un mAddr;
+};
+
bool RpcConnection::setupUnixDomainServer(const char* path) {
- LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Only supports one server now");
-
- unique_fd serverFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
- if (serverFd == -1) {
- ALOGE("Could not create socket at %s: %s", path, strerror(errno));
- return false;
- }
-
- struct sockaddr_un addr = {
- .sun_family = AF_UNIX,
- };
-
- unsigned int pathLen = strlen(path) + 1;
- LOG_ALWAYS_FATAL_IF(pathLen > sizeof(addr.sun_path), "%u", pathLen);
- memcpy(addr.sun_path, path, pathLen);
-
- if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), (struct sockaddr*)&addr, sizeof(addr)))) {
- ALOGE("Could not bind socket at %s: %s", path, strerror(errno));
- return false;
- }
-
- if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
- ALOGE("Could not listen socket at %s: %s", path, strerror(errno));
- return false;
- }
-
- mServer = std::move(serverFd);
- return true;
+ return addServer(UnixSocketAddress(path));
}
bool RpcConnection::addUnixDomainClient(const char* path) {
- LOG_RPC_DETAIL("Connecting on path: %s", path);
-
- unique_fd serverFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
- if (serverFd == -1) {
- ALOGE("Could not create socket at %s: %s", path, strerror(errno));
- return false;
- }
-
- struct sockaddr_un addr = {
- .sun_family = AF_UNIX,
- };
-
- unsigned int pathLen = strlen(path) + 1;
- LOG_ALWAYS_FATAL_IF(pathLen > sizeof(addr.sun_path), "%u", pathLen);
- memcpy(addr.sun_path, path, pathLen);
-
- if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), (struct sockaddr*)&addr, sizeof(addr)))) {
- ALOGE("Could not connect socket at %s: %s", path, strerror(errno));
- return false;
- }
-
- LOG_RPC_DETAIL("Unix domain client with fd %d", serverFd.get());
-
- addClient(std::move(serverFd));
- return true;
+ return addClient(UnixSocketAddress(path));
}
+#ifdef __BIONIC__
+
+class VsockSocketAddress : public RpcConnection::SocketAddress {
+public:
+ VsockSocketAddress(unsigned int cid, unsigned int port)
+ : mAddr({
+ .svm_family = AF_VSOCK,
+ .svm_port = port,
+ .svm_cid = cid,
+ }) {}
+ virtual ~VsockSocketAddress() {}
+ std::string toString() const override {
+ return String8::format("cid %du port %du", mAddr.svm_cid, mAddr.svm_port).c_str();
+ }
+ const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+ size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+ sockaddr_vm mAddr;
+};
+
+bool RpcConnection::setupVsockServer(unsigned int port) {
+ // realizing value w/ this type at compile time to avoid ubsan abort
+ constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
+
+ return addServer(VsockSocketAddress(kAnyCid, port));
+}
+
+bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) {
+ return addClient(VsockSocketAddress(cid, port));
+}
+
+#endif // __BIONIC__
+
sp<IBinder> RpcConnection::getRootObject() {
ExclusiveSocket socket(this, SocketUse::CLIENT);
return state()->getRootObject(socket.fd(), this);
@@ -130,11 +140,8 @@
void RpcConnection::join() {
// establish a connection
{
- struct sockaddr_un clientSa;
- socklen_t clientSaLen = sizeof(clientSa);
-
- unique_fd clientFd(TEMP_FAILURE_RETRY(
- accept4(mServer.get(), (struct sockaddr*)&clientSa, &clientSaLen, SOCK_CLOEXEC)));
+ unique_fd clientFd(
+ TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
if (clientFd < 0) {
// If this log becomes confusing, should save more state from setupUnixDomainServer
// in order to output here.
@@ -144,7 +151,7 @@
LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
- addServer(std::move(clientFd));
+ assignServerToThisThread(std::move(clientFd));
}
// We may not use the connection we just established (two threads might
@@ -170,14 +177,57 @@
return mForServer;
}
-void RpcConnection::addClient(base::unique_fd&& fd) {
- std::lock_guard<std::mutex> _l(mSocketMutex);
- sp<ConnectionSocket> connection = new ConnectionSocket();
- connection->fd = std::move(fd);
- mClients.push_back(connection);
+bool RpcConnection::addServer(const SocketAddress& addr) {
+ LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server.");
+
+ unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ if (serverFd == -1) {
+ ALOGE("Could not create socket: %s", strerror(errno));
+ return false;
+ }
+
+ if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ int savedErrno = errno;
+ ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
+ int savedErrno = errno;
+ ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ mServer = std::move(serverFd);
+ return true;
}
-void RpcConnection::addServer(base::unique_fd&& fd) {
+bool RpcConnection::addClient(const SocketAddress& addr) {
+ unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ if (serverFd == -1) {
+ int savedErrno = errno;
+ ALOGE("Could not create socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ int savedErrno = errno;
+ ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
+
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ sp<ConnectionSocket> connection = new ConnectionSocket();
+ connection->fd = std::move(serverFd);
+ mClients.push_back(connection);
+ return true;
+}
+
+void RpcConnection::assignServerToThisThread(base::unique_fd&& fd) {
std::lock_guard<std::mutex> _l(mSocketMutex);
sp<ConnectionSocket> connection = new ConnectionSocket();
connection->fd = std::move(fd);
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 64e842e..3b3adca 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -192,7 +192,7 @@
return false;
}
- ssize_t sent = TEMP_FAILURE_RETRY(send(fd.get(), data, size, 0));
+ ssize_t sent = TEMP_FAILURE_RETRY(send(fd.get(), data, size, MSG_NOSIGNAL));
if (sent < 0 || sent != static_cast<ssize_t>(size)) {
ALOGE("Failed to send %s (sent %zd of %zu bytes) on fd %d, error: %s", what, sent, size,
@@ -212,7 +212,7 @@
return false;
}
- ssize_t recd = TEMP_FAILURE_RETRY(recv(fd.get(), data, size, MSG_WAITALL));
+ ssize_t recd = TEMP_FAILURE_RETRY(recv(fd.get(), data, size, MSG_WAITALL | MSG_NOSIGNAL));
if (recd < 0 || recd != static_cast<ssize_t>(size)) {
terminate();
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index c3f1ba7..f12ef4e 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -38,18 +38,30 @@
};
}
-void Stability::forceDowngradeCompilationUnit(const sp<IBinder>& binder) {
+void Stability::forceDowngradeToStability(const sp<IBinder>& binder, Level level) {
// Downgrading a remote binder would require also copying the version from
// the binder sent here. In practice though, we don't need to downgrade the
// stability of a remote binder, since this would as an effect only restrict
// what we can do to it.
LOG_ALWAYS_FATAL_IF(!binder || !binder->localBinder(), "Can only downgrade local binder");
- auto stability = Category::currentFromLevel(getLocalLevel());
+ auto stability = Category::currentFromLevel(level);
status_t result = setRepr(binder.get(), stability.repr(), REPR_LOG | REPR_ALLOW_DOWNGRADE);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
+void Stability::forceDowngradeToLocalStability(const sp<IBinder>& binder) {
+ forceDowngradeToStability(binder, getLocalLevel());
+}
+
+void Stability::forceDowngradeToSystemStability(const sp<IBinder>& binder) {
+ forceDowngradeToStability(binder, Level::SYSTEM);
+}
+
+void Stability::forceDowngradeToVendorStability(const sp<IBinder>& binder) {
+ forceDowngradeToStability(binder, Level::VENDOR);
+}
+
std::string Stability::Category::debugString() {
return levelString(level) + " wire protocol version "
+ std::to_string(version);
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index eac1bb2..be6667d 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -143,7 +143,8 @@
OP_COARSE_LOCATION_SOURCE = 109,
OP_MANAGE_MEDIA = 110,
OP_BLUETOOTH_CONNECT = 111,
- _NUM_OP = 112
+ OP_UWB_RANGING = 112,
+ _NUM_OP = 113
};
AppOpsManager();
diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h
deleted file mode 100644
index f92d557..0000000
--- a/libs/binder/include/binder/IMediaResourceMonitor.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifndef __ANDROID_VNDK__
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IMediaResourceMonitor : public IInterface {
-public:
- DECLARE_META_INTERFACE(MediaResourceMonitor)
-
- // Values should be in sync with Intent.EXTRA_MEDIA_RESOURCE_TYPE_XXX.
- enum {
- TYPE_VIDEO_CODEC = 0,
- TYPE_AUDIO_CODEC = 1,
- };
-
- virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0;
-
- enum {
- NOTIFY_RESOURCE_GRANTED = IBinder::FIRST_CALL_TRANSACTION,
- };
-};
-
-// ----------------------------------------------------------------------
-
-class BnMediaResourceMonitor : public BnInterface<IMediaResourceMonitor> {
-public:
- // NOLINTNEXTLINE(google-default-arguments)
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-} // namespace android
-
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
index 65c5232..a300575 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -61,6 +61,18 @@
*/
[[nodiscard]] bool addUnixDomainClient(const char* path);
+#ifdef __BIONIC__
+ /**
+ * Creates an RPC server at the current port.
+ */
+ [[nodiscard]] bool setupVsockServer(unsigned int port);
+
+ /**
+ * Connects to an RPC server at the CVD & port.
+ */
+ [[nodiscard]] bool addVsockClient(unsigned int cvd, unsigned int port);
+#endif // __BIONIC__
+
/**
* Query the other side of the connection for the root object hosted by that
* process's RpcServer (if one exists)
@@ -85,11 +97,20 @@
// internal only
const std::unique_ptr<RpcState>& state() { return mState; }
+ class SocketAddress {
+ public:
+ virtual ~SocketAddress();
+ virtual std::string toString() const = 0;
+ virtual const sockaddr* addr() const = 0;
+ virtual size_t addrSize() const = 0;
+ };
+
private:
RpcConnection();
- void addServer(base::unique_fd&& fd);
- void addClient(base::unique_fd&& fd);
+ bool addServer(const SocketAddress& address);
+ bool addClient(const SocketAddress& address);
+ void assignServerToThisThread(base::unique_fd&& fd);
struct ConnectionSocket : public RefBase {
base::unique_fd fd;
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index a09e587..1831ffc 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -54,8 +54,33 @@
// Given a binder interface at a certain stability, there may be some
// requirements associated with that higher stability level. For instance, a
// VINTF stability binder is required to be in the VINTF manifest. This API
- // can be called to use that same interface within a partition.
- static void forceDowngradeCompilationUnit(const sp<IBinder>& binder);
+ // can be called to use that same interface within the local partition.
+ static void forceDowngradeToLocalStability(const sp<IBinder>& binder);
+
+ // WARNING: The only client of
+ // - forceDowngradeToSystemStability() and;
+ // - korceDowngradeToVendorStability()
+ // should be AIBinder_forceDowngradeToLocalStability().
+ //
+ // getLocalLevel() in libbinder returns Level::SYSTEM when called
+ // from libbinder_ndk (even on vendor partition). So we explicitly provide
+ // these methods for use by the NDK API:
+ // AIBinder_forceDowngradeToLocalStability().
+ //
+ // This allows correctly downgrading the binder's stability to either system/vendor,
+ // depending on the partition.
+
+ // Given a binder interface at a certain stability, there may be some
+ // requirements associated with that higher stability level. For instance, a
+ // VINTF stability binder is required to be in the VINTF manifest. This API
+ // can be called to use that same interface within the vendor partition.
+ static void forceDowngradeToVendorStability(const sp<IBinder>& binder);
+
+ // Given a binder interface at a certain stability, there may be some
+ // requirements associated with that higher stability level. For instance, a
+ // VINTF stability binder is required to be in the VINTF manifest. This API
+ // can be called to use that same interface within the system partition.
+ static void forceDowngradeToSystemStability(const sp<IBinder>& binder);
// WARNING: Below APIs are only ever expected to be called by auto-generated code.
// Instead of calling them, you should set the stability of a .aidl interface
@@ -146,6 +171,9 @@
// returns the stability according to how this was built
static Level getLocalLevel();
+ // Downgrades binder stability to the specified level.
+ static void forceDowngradeToStability(const sp<IBinder>& binder, Level level);
+
enum {
REPR_NONE = 0,
REPR_LOG = 1,
diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include_processinfo/processinfo/IProcessInfoService.h
similarity index 100%
rename from libs/binder/include/binder/IProcessInfoService.h
rename to libs/binder/include_processinfo/processinfo/IProcessInfoService.h
diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include_processinfo/processinfo/ProcessInfoService.h
similarity index 98%
rename from libs/binder/include/binder/ProcessInfoService.h
rename to libs/binder/include_processinfo/processinfo/ProcessInfoService.h
index 6b3b5ce..978856d 100644
--- a/libs/binder/include/binder/ProcessInfoService.h
+++ b/libs/binder/include_processinfo/processinfo/ProcessInfoService.h
@@ -18,7 +18,7 @@
#ifndef __ANDROID_VNDK__
-#include <binder/IProcessInfoService.h>
+#include <processinfo/IProcessInfoService.h>
#include <utils/Errors.h>
#include <utils/Singleton.h>
#include <sys/types.h>
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index ce7255e..f113ba8 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -45,6 +45,18 @@
AIBinder_markVendorStability(binder);
}
+/**
+ * Given a binder interface at a certain stability, there may be some
+ * requirements associated with that higher stability level. For instance, a
+ * VINTF stability binder is required to be in the VINTF manifest. This API
+ * can be called to use that same interface within the vendor partition.
+ */
+void AIBinder_forceDowngradeToVendorStability(AIBinder* binder);
+
+static inline void AIBinder_forceDowngradeToLocalStability(AIBinder* binder) {
+ AIBinder_forceDowngradeToVendorStability(binder);
+}
+
#else // defined(__ANDROID_VENDOR__)
enum {
@@ -62,9 +74,27 @@
AIBinder_markSystemStability(binder);
}
+/**
+ * Given a binder interface at a certain stability, there may be some
+ * requirements associated with that higher stability level. For instance, a
+ * VINTF stability binder is required to be in the VINTF manifest. This API
+ * can be called to use that same interface within the system partition.
+ */
+void AIBinder_forceDowngradeToSystemStability(AIBinder* binder);
+
+static inline void AIBinder_forceDowngradeToLocalStability(AIBinder* binder) {
+ AIBinder_forceDowngradeToSystemStability(binder);
+}
+
#endif // defined(__ANDROID_VENDOR__)
/**
+ * WARNING: this is not expected to be used manually. When the build system has
+ * versioned checks in place for an interface that prevent it being changed year
+ * over year (specifically like those for @VintfStability stable AIDL
+ * interfaces), this could be called. Calling this without this or equivalent
+ * infrastructure will lead to de facto frozen APIs or GSI test failures.
+ *
* This interface has system<->vendor stability
*/
void AIBinder_markVintfStability(AIBinder* binder);
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f1db653..67c85b6 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -127,6 +127,9 @@
AServiceManager_tryUnregister; # llndk
AServiceManager_reRegister; # llndk
+ AIBinder_forceDowngradeToSystemStability; # apex
+ AIBinder_forceDowngradeToVendorStability; # llndk
+
AIBinder_Class_getDescriptor;
AIBinder_Weak_clone;
AIBinder_Weak_lt;
diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h
index 6b7295e..aebc7f4 100644
--- a/libs/binder/ndk/parcel_internal.h
+++ b/libs/binder/ndk/parcel_internal.h
@@ -27,10 +27,13 @@
const ::android::Parcel* get() const { return mParcel; }
::android::Parcel* get() { return mParcel; }
- explicit AParcel(const AIBinder* binder)
- : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
- AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
- : mBinder(binder), mParcel(parcel), mOwns(owns) {}
+ explicit AParcel(AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
+ AParcel(AIBinder* binder, ::android::Parcel* parcel, bool owns)
+ : mBinder(binder), mParcel(parcel), mOwns(owns) {
+ if (binder != nullptr) {
+ parcel->markForBinder(binder->getBinder());
+ }
+ }
~AParcel() {
if (mOwns) {
@@ -38,7 +41,7 @@
}
}
- static const AParcel readOnly(const AIBinder* binder, const ::android::Parcel* parcel) {
+ static const AParcel readOnly(AIBinder* binder, const ::android::Parcel* parcel) {
return AParcel(binder, const_cast<::android::Parcel*>(parcel), false);
}
diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp
index a5b3ece..7eafb9c 100644
--- a/libs/binder/ndk/stability.cpp
+++ b/libs/binder/ndk/stability.cpp
@@ -31,7 +31,7 @@
#error libbinder_ndk should only be built in a system context
#endif
-// explicit extern because symbol is only declared in header when __ANDROID_VNDK__
+// explicit extern because symbol is only declared in header when __ANDROID_VENDOR__
extern "C" void AIBinder_markVendorStability(AIBinder* binder) {
Stability::markVndk(binder->getBinder().get());
}
@@ -43,3 +43,12 @@
void AIBinder_markVintfStability(AIBinder* binder) {
Stability::markVintf(binder->getBinder().get());
}
+
+// explicit extern because symbol is only declared in header when __ANDROID_VENDOR__
+extern "C" void AIBinder_forceDowngradeToVendorStability(AIBinder* binder) {
+ Stability::forceDowngradeToVendorStability(binder->getBinder());
+}
+
+void AIBinder_forceDowngradeToSystemStability(AIBinder* binder) {
+ Stability::forceDowngradeToSystemStability(binder->getBinder());
+}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index a44cddf..afc4b1b 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -104,22 +104,49 @@
require_root: true,
}
-cc_test {
- name: "binderRpcTest",
- defaults: ["binder_test_defaults"],
-
+aidl_interface {
+ name: "binderRpcTestIface",
+ host_supported: true,
+ unstable: true,
srcs: [
"IBinderRpcSession.aidl",
"IBinderRpcTest.aidl",
+ ],
+ backend: {
+ java: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test {
+ name: "binderRpcTest",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ defaults: [
+ "binder_test_defaults",
+ "libbinder_ndk_host_user",
+ ],
+
+ srcs: [
"binderRpcTest.cpp",
],
shared_libs: [
"libbinder",
+ "libbinder_ndk",
"libbase",
"libutils",
"libcutils",
"liblog",
],
+ static_libs: [
+ "binderRpcTestIface-cpp",
+ "binderRpcTestIface-ndk_platform",
+ ],
test_suites: ["general-tests"],
require_root: true,
}
@@ -210,6 +237,11 @@
srcs: [
"IBinderStabilityTest.aidl",
],
+ backend: {
+ java: {
+ enabled: false,
+ },
+ },
}
cc_test {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 6fa5333..5f68a25 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,17 +14,12 @@
* limitations under the License.
*/
-#include <sys/prctl.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <cstdlib>
-#include <iostream>
-#include <thread>
-
#include <BnBinderRpcSession.h>
#include <BnBinderRpcTest.h>
+#include <aidl/IBinderRpcTest.h>
#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_libbinder.h>
#include <binder/Binder.h>
#include <binder/BpBinder.h>
#include <binder/IServiceManager.h>
@@ -33,6 +28,18 @@
#include <binder/RpcServer.h>
#include <gtest/gtest.h>
+#include <chrono>
+#include <cstdlib>
+#include <iostream>
+#include <thread>
+
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#endif //__BIONIC__
+
+#include <sys/prctl.h>
+#include <unistd.h>
+
#include "../RpcState.h" // for debugging
namespace android {
@@ -185,8 +192,13 @@
static std::string allocateSocketAddress() {
static size_t id = 0;
+ static bool gUseTmp = access("/tmp/", F_OK) != -1;
- return "/dev/binderRpcTest_" + std::to_string(id++);
+ if (gUseTmp) {
+ return "/tmp/binderRpcTest_" + std::to_string(id++);
+ } else {
+ return "/dev/binderRpcTest_" + std::to_string(id++);
+ }
};
struct ProcessConnection {
@@ -214,58 +226,6 @@
}
};
-// This creates a new process serving an interface on a certain number of
-// threads.
-ProcessConnection createRpcTestSocketServerProcess(
- size_t numThreads,
- const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
- CHECK_GT(numThreads, 0);
-
- std::string addr = allocateSocketAddress();
- unlink(addr.c_str());
-
- auto ret = ProcessConnection{
- .host = Process([&] {
- sp<RpcServer> server = RpcServer::make();
-
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-
- // server supporting one client on one socket
- sp<RpcConnection> connection = server->addClientConnection();
- CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr;
-
- configure(server, connection);
-
- // accept 'numThreads' connections
- std::vector<std::thread> pool;
- for (size_t i = 0; i + 1 < numThreads; i++) {
- pool.push_back(std::thread([=] { connection->join(); }));
- }
- connection->join();
- for (auto& t : pool) t.join();
- }),
- .connection = RpcConnection::make(),
- };
-
- // wait up to 1s for sockets to be created
- constexpr useconds_t kMaxWaitUs = 1000000;
- constexpr useconds_t kWaitDivision = 100;
- for (size_t i = 0; i < kWaitDivision && 0 != access(addr.c_str(), F_OK); i++) {
- usleep(kMaxWaitUs / kWaitDivision);
- }
-
- // create remainder of connections
- for (size_t i = 0; i < numThreads; i++) {
- // Connection refused sometimes after file created but before listening.
- CHECK(ret.connection->addUnixDomainClient(addr.c_str()) ||
- (usleep(10000), ret.connection->addUnixDomainClient(addr.c_str())))
- << i;
- }
-
- ret.rootBinder = ret.connection->getRootObject();
- return ret;
-}
-
// Process connection where the process hosts IBinderRpcTest, the server used
// for most testing here
struct BinderRpcTestProcessConnection {
@@ -290,26 +250,122 @@
}
};
-BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
- BinderRpcTestProcessConnection ret{
- .proc = createRpcTestSocketServerProcess(numThreads,
- [&](const sp<RpcServer>& server,
- const sp<RpcConnection>& connection) {
- sp<MyBinderRpcTest> service =
- new MyBinderRpcTest;
- server->setRootObject(service);
- service->connection =
- connection; // for testing only
- }),
- };
-
- ret.rootBinder = ret.proc.rootBinder;
- ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
-
- return ret;
+enum class SocketType {
+ UNIX,
+#ifdef __BIONIC__
+ VSOCK,
+#endif // __BIONIC__
+};
+static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
+ switch (info.param) {
+ case SocketType::UNIX:
+ return "unix_domain_socket";
+#ifdef __BIONIC__
+ case SocketType::VSOCK:
+ return "vm_socket";
+#endif // __BIONIC__
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ return "";
+ }
}
+class BinderRpc : public ::testing::TestWithParam<SocketType> {
+public:
+ // This creates a new process serving an interface on a certain number of
+ // threads.
+ ProcessConnection createRpcTestSocketServerProcess(
+ size_t numThreads,
+ const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
+ CHECK_GT(numThreads, 0);
-TEST(BinderRpc, RootObjectIsNull) {
+ SocketType socketType = GetParam();
+
+ std::string addr = allocateSocketAddress();
+ unlink(addr.c_str());
+ static unsigned int port = 3456;
+ port++;
+
+ auto ret = ProcessConnection{
+ .host = Process([&] {
+ sp<RpcServer> server = RpcServer::make();
+
+ server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+
+ // server supporting one client on one socket
+ sp<RpcConnection> connection = server->addClientConnection();
+
+ switch (socketType) {
+ case SocketType::UNIX:
+ CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr;
+ break;
+#ifdef __BIONIC__
+ case SocketType::VSOCK:
+ CHECK(connection->setupVsockServer(port));
+ break;
+#endif // __BIONIC__
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ }
+
+ configure(server, connection);
+
+ // accept 'numThreads' connections
+ std::vector<std::thread> pool;
+ for (size_t i = 0; i + 1 < numThreads; i++) {
+ pool.push_back(std::thread([=] { connection->join(); }));
+ }
+ connection->join();
+ for (auto& t : pool) t.join();
+ }),
+ .connection = RpcConnection::make(),
+ };
+
+ // create remainder of connections
+ for (size_t i = 0; i < numThreads; i++) {
+ for (size_t tries = 0; tries < 5; tries++) {
+ usleep(10000);
+ switch (socketType) {
+ case SocketType::UNIX:
+ if (ret.connection->addUnixDomainClient(addr.c_str())) goto success;
+ break;
+#ifdef __BIONIC__
+ case SocketType::VSOCK:
+ if (ret.connection->addVsockClient(VMADDR_CID_LOCAL, port)) goto success;
+ break;
+#endif // __BIONIC__
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ }
+ }
+ LOG_ALWAYS_FATAL("Could not connect");
+ success:;
+ }
+
+ ret.rootBinder = ret.connection->getRootObject();
+ return ret;
+ }
+
+ BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
+ BinderRpcTestProcessConnection ret{
+ .proc = createRpcTestSocketServerProcess(numThreads,
+ [&](const sp<RpcServer>& server,
+ const sp<RpcConnection>& connection) {
+ sp<MyBinderRpcTest> service =
+ new MyBinderRpcTest;
+ server->setRootObject(service);
+ service->connection =
+ connection; // for testing only
+ }),
+ };
+
+ ret.rootBinder = ret.proc.rootBinder;
+ ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
+
+ return ret;
+ }
+};
+
+TEST_P(BinderRpc, RootObjectIsNull) {
auto proc = createRpcTestSocketServerProcess(1,
[](const sp<RpcServer>& server,
const sp<RpcConnection>&) {
@@ -324,20 +380,26 @@
EXPECT_EQ(nullptr, proc.connection->getRootObject());
}
-TEST(BinderRpc, Ping) {
+TEST_P(BinderRpc, Ping) {
auto proc = createRpcTestSocketServerProcess(1);
ASSERT_NE(proc.rootBinder, nullptr);
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
}
-TEST(BinderRpc, TransactionsMustBeMarkedRpc) {
+TEST_P(BinderRpc, GetInterfaceDescriptor) {
+ auto proc = createRpcTestSocketServerProcess(1);
+ ASSERT_NE(proc.rootBinder, nullptr);
+ EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
+}
+
+TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
auto proc = createRpcTestSocketServerProcess(1);
Parcel data;
Parcel reply;
EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
}
-TEST(BinderRpc, UnknownTransaction) {
+TEST_P(BinderRpc, UnknownTransaction) {
auto proc = createRpcTestSocketServerProcess(1);
Parcel data;
data.markForBinder(proc.rootBinder);
@@ -345,19 +407,19 @@
EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
}
-TEST(BinderRpc, SendSomethingOneway) {
+TEST_P(BinderRpc, SendSomethingOneway) {
auto proc = createRpcTestSocketServerProcess(1);
EXPECT_OK(proc.rootIface->sendString("asdf"));
}
-TEST(BinderRpc, SendAndGetResultBack) {
+TEST_P(BinderRpc, SendAndGetResultBack) {
auto proc = createRpcTestSocketServerProcess(1);
std::string doubled;
EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
EXPECT_EQ("cool cool ", doubled);
}
-TEST(BinderRpc, SendAndGetResultBackBig) {
+TEST_P(BinderRpc, SendAndGetResultBackBig) {
auto proc = createRpcTestSocketServerProcess(1);
std::string single = std::string(1024, 'a');
std::string doubled;
@@ -365,7 +427,7 @@
EXPECT_EQ(single + single, doubled);
}
-TEST(BinderRpc, CallMeBack) {
+TEST_P(BinderRpc, CallMeBack) {
auto proc = createRpcTestSocketServerProcess(1);
int32_t pingResult;
@@ -375,7 +437,7 @@
EXPECT_EQ(0, MyBinderRpcSession::gNum);
}
-TEST(BinderRpc, RepeatBinder) {
+TEST_P(BinderRpc, RepeatBinder) {
auto proc = createRpcTestSocketServerProcess(1);
sp<IBinder> inBinder = new MyBinderRpcSession("foo");
@@ -397,7 +459,7 @@
EXPECT_EQ(0, MyBinderRpcSession::gNum);
}
-TEST(BinderRpc, RepeatTheirBinder) {
+TEST_P(BinderRpc, RepeatTheirBinder) {
auto proc = createRpcTestSocketServerProcess(1);
sp<IBinderRpcSession> session;
@@ -421,7 +483,7 @@
EXPECT_EQ(nullptr, weak.promote());
}
-TEST(BinderRpc, RepeatBinderNull) {
+TEST_P(BinderRpc, RepeatBinderNull) {
auto proc = createRpcTestSocketServerProcess(1);
sp<IBinder> outBinder;
@@ -429,7 +491,7 @@
EXPECT_EQ(nullptr, outBinder);
}
-TEST(BinderRpc, HoldBinder) {
+TEST_P(BinderRpc, HoldBinder) {
auto proc = createRpcTestSocketServerProcess(1);
IBinder* ptr = nullptr;
@@ -455,7 +517,7 @@
// These are behavioral differences form regular binder, where certain usecases
// aren't supported.
-TEST(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) {
+TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) {
auto proc1 = createRpcTestSocketServerProcess(1);
auto proc2 = createRpcTestSocketServerProcess(1);
@@ -464,7 +526,7 @@
proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
}
-TEST(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
auto proc = createRpcTestSocketServerProcess(1);
sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
@@ -473,7 +535,7 @@
proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
}
-TEST(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
auto proc = createRpcTestSocketServerProcess(1);
// for historical reasons, IServiceManager interface only returns the
@@ -484,7 +546,7 @@
// END TESTS FOR LIMITATIONS OF SOCKET BINDER
-TEST(BinderRpc, RepeatRootObject) {
+TEST_P(BinderRpc, RepeatRootObject) {
auto proc = createRpcTestSocketServerProcess(1);
sp<IBinder> outBinder;
@@ -492,7 +554,7 @@
EXPECT_EQ(proc.rootBinder, outBinder);
}
-TEST(BinderRpc, NestedTransactions) {
+TEST_P(BinderRpc, NestedTransactions) {
auto proc = createRpcTestSocketServerProcess(1);
auto nastyNester = sp<MyBinderRpcTest>::make();
@@ -503,7 +565,7 @@
EXPECT_EQ(nullptr, weak.promote());
}
-TEST(BinderRpc, SameBinderEquality) {
+TEST_P(BinderRpc, SameBinderEquality) {
auto proc = createRpcTestSocketServerProcess(1);
sp<IBinder> a;
@@ -515,7 +577,7 @@
EXPECT_EQ(a, b);
}
-TEST(BinderRpc, SameBinderEqualityWeak) {
+TEST_P(BinderRpc, SameBinderEqualityWeak) {
auto proc = createRpcTestSocketServerProcess(1);
sp<IBinder> a;
@@ -547,7 +609,7 @@
EXPECT_EQ(expected, session); \
} while (false)
-TEST(BinderRpc, SingleSession) {
+TEST_P(BinderRpc, SingleSession) {
auto proc = createRpcTestSocketServerProcess(1);
sp<IBinderRpcSession> session;
@@ -561,7 +623,7 @@
expectSessions(0, proc.rootIface);
}
-TEST(BinderRpc, ManySessions) {
+TEST_P(BinderRpc, ManySessions) {
auto proc = createRpcTestSocketServerProcess(1);
std::vector<sp<IBinderRpcSession>> sessions;
@@ -595,7 +657,7 @@
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
-TEST(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
+TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
constexpr size_t kNumThreads = 10;
auto proc = createRpcTestSocketServerProcess(kNumThreads);
@@ -627,7 +689,7 @@
for (auto& t : ts) t.join();
}
-TEST(BinderRpc, ThreadPoolOverSaturated) {
+TEST_P(BinderRpc, ThreadPoolOverSaturated) {
constexpr size_t kNumThreads = 10;
constexpr size_t kNumCalls = kNumThreads + 3;
constexpr size_t kSleepMs = 500;
@@ -651,7 +713,7 @@
EXPECT_LE(epochMsAfter, epochMsBefore + 3 * kSleepMs);
}
-TEST(BinderRpc, ThreadingStressTest) {
+TEST_P(BinderRpc, ThreadingStressTest) {
constexpr size_t kNumClientThreads = 10;
constexpr size_t kNumServerThreads = 10;
constexpr size_t kNumCalls = 100;
@@ -672,7 +734,7 @@
for (auto& t : threads) t.join();
}
-TEST(BinderRpc, OnewayCallDoesNotWait) {
+TEST_P(BinderRpc, OnewayCallDoesNotWait) {
constexpr size_t kReallyLongTimeMs = 100;
constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
@@ -687,7 +749,7 @@
EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
}
-TEST(BinderRpc, OnewayCallQueueing) {
+TEST_P(BinderRpc, OnewayCallQueueing) {
constexpr size_t kNumSleeps = 10;
constexpr size_t kNumExtraServerThreads = 4;
constexpr size_t kSleepMs = 50;
@@ -711,10 +773,7 @@
EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
}
-TEST(BinderRpc, Die) {
- // TODO(b/183141167): handle this in library
- signal(SIGPIPE, SIG_IGN);
-
+TEST_P(BinderRpc, Die) {
for (bool doDeathCleanup : {true, false}) {
auto proc = createRpcTestSocketServerProcess(1);
@@ -733,6 +792,30 @@
}
}
+TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
+ ASSERT_NE(binder, nullptr);
+
+ ASSERT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+}
+
+TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
+ ASSERT_NE(binder, nullptr);
+
+ auto ndkBinder = aidl::IBinderRpcTest::fromBinder(binder);
+ ASSERT_NE(ndkBinder, nullptr);
+
+ std::string out;
+ ndk::ScopedAStatus status = ndkBinder->doubleString("aoeu", &out);
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
+ ASSERT_EQ("aoeuaoeu", out);
+}
+
ssize_t countFds() {
DIR* dir = opendir("/proc/self/fd/");
if (dir == nullptr) return -1;
@@ -743,7 +826,7 @@
return ret;
}
-TEST(BinderRpc, Fds) {
+TEST_P(BinderRpc, Fds) {
ssize_t beforeFds = countFds();
ASSERT_GE(beforeFds, 0);
{
@@ -753,10 +836,19 @@
ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
}
-extern "C" int main(int argc, char** argv) {
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
+ ::testing::Values(SocketType::UNIX
+#ifdef __BIONIC__
+ ,
+ SocketType::VSOCK
+#endif // __BIONIC__
+ ),
+ PrintSocketType);
+
+} // namespace android
+
+int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter);
return RUN_ALL_TESTS();
}
-
-} // namespace android
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 4270540..dbd3f4e 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android/binder_libbinder.h>
#include <android/binder_manager.h>
#include <android/binder_stability.h>
#include <binder/Binder.h>
@@ -137,7 +138,18 @@
EXPECT_TRUE(Stability::requiresVintfDeclaration(someBinder));
// silly to do this after already using the binder, but it's for the test
- Stability::forceDowngradeCompilationUnit(someBinder);
+ Stability::forceDowngradeToLocalStability(someBinder);
+
+ EXPECT_FALSE(Stability::requiresVintfDeclaration(someBinder));
+}
+
+TEST(BinderStability, NdkForceDowngradeStability) {
+ sp<IBinder> someBinder = BadStableBinder::vintf();
+
+ EXPECT_TRUE(Stability::requiresVintfDeclaration(someBinder));
+
+ // silly to do this after already using the binder, but it's for the test
+ AIBinder_forceDowngradeToLocalStability(AIBinder_fromPlatformBinder(someBinder));
EXPECT_FALSE(Stability::requiresVintfDeclaration(someBinder));
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index c1e3385..454aa9e 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -982,6 +982,34 @@
return NO_ERROR;
}
+ status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, displayToken);
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
+ const status_t error =
+ remote()->transact(BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER, data, &reply);
+ if (error != OK) {
+ ALOGE("addHdrLayerInfoListener: Failed to transact; error = %d", error);
+ }
+ return error;
+ }
+
+ status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, displayToken);
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
+ const status_t error =
+ remote()->transact(BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER, data, &reply);
+ if (error != OK) {
+ ALOGE("removeHdrLayerInfoListener: Failed to transact; error = %d", error);
+ }
+ return error;
+ }
+
status_t notifyPowerBoost(int32_t boostId) override {
Parcel data, reply;
status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -1838,6 +1866,38 @@
}
return setDisplayBrightness(displayToken, brightness);
}
+ case ADD_HDR_LAYER_INFO_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> displayToken;
+ status_t error = data.readNullableStrongBinder(&displayToken);
+ if (error != NO_ERROR) {
+ ALOGE("addHdrLayerInfoListener: Failed to read display token");
+ return error;
+ }
+ sp<gui::IHdrLayerInfoListener> listener;
+ error = data.readNullableStrongBinder(&listener);
+ if (error != NO_ERROR) {
+ ALOGE("addHdrLayerInfoListener: Failed to read listener");
+ return error;
+ }
+ return addHdrLayerInfoListener(displayToken, listener);
+ }
+ case REMOVE_HDR_LAYER_INFO_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> displayToken;
+ status_t error = data.readNullableStrongBinder(&displayToken);
+ if (error != NO_ERROR) {
+ ALOGE("removeHdrLayerInfoListener: Failed to read display token");
+ return error;
+ }
+ sp<gui::IHdrLayerInfoListener> listener;
+ error = data.readNullableStrongBinder(&listener);
+ if (error != NO_ERROR) {
+ ALOGE("removeHdrLayerInfoListener: Failed to read listener");
+ return error;
+ }
+ return removeHdrLayerInfoListener(displayToken, listener);
+ }
case NOTIFY_POWER_BOOST: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
int32_t boostId;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index cb8028b..879955b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2054,6 +2054,17 @@
return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
}
+status_t SurfaceComposerClient::addHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ return ComposerService::getComposerService()->addHdrLayerInfoListener(displayToken, listener);
+}
+
+status_t SurfaceComposerClient::removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ return ComposerService::getComposerService()->removeHdrLayerInfoListener(displayToken,
+ listener);
+}
+
status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) {
return ComposerService::getComposerService()->notifyPowerBoost(boostId);
}
diff --git a/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl b/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl
new file mode 100644
index 0000000..fc809c4
--- /dev/null
+++ b/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+/** @hide */
+oneway interface IHdrLayerInfoListener {
+ // Callback with the total number of HDR layers, the dimensions of the largest layer,
+ // and a placeholder flags
+ // TODO (b/182312559): Define the flags (likely need an indicator that a UDFPS layer is present)
+ void onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH, int flags);
+}
\ No newline at end of file
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index d933514..ccd6d4e 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -18,6 +18,7 @@
#include <android/gui/DisplayBrightness.h>
#include <android/gui/IFpsListener.h>
+#include <android/gui/IHdrLayerInfoListener.h>
#include <android/gui/IScreenCaptureListener.h>
#include <android/gui/ITransactionTraceListener.h>
#include <binder/IBinder.h>
@@ -431,6 +432,25 @@
const gui::DisplayBrightness& brightness) = 0;
/*
+ * Adds a listener that receives HDR layer information. This is used in combination
+ * with setDisplayBrightness to adjust the display brightness depending on factors such
+ * as whether or not HDR is in use.
+ *
+ * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
+ */
+ virtual status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) = 0;
+ /*
+ * Removes a listener that was added with addHdrLayerInfoListener.
+ *
+ * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
+ * the listener wasn't registered.
+ *
+ */
+ virtual status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) = 0;
+
+ /*
* Sends a power boost to the composer. This function is asynchronous.
*
* boostId
@@ -578,6 +598,8 @@
ADD_FPS_LISTENER,
REMOVE_FPS_LISTENER,
OVERRIDE_HDR_TYPES,
+ ADD_HDR_LAYER_INFO_LISTENER,
+ REMOVE_HDR_LAYER_INFO_LISTENER,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 35f57a2..7ec5d8d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -215,6 +215,11 @@
static status_t setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness);
+ static status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener);
+ static status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener);
+
/*
* Sends a power boost to the composer. This function is asynchronous.
*
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8876033..751b95a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -819,6 +819,16 @@
return NO_ERROR;
}
+ status_t addHdrLayerInfoListener(const sp<IBinder>&,
+ const sp<gui::IHdrLayerInfoListener>&) override {
+ return NO_ERROR;
+ }
+
+ status_t removeHdrLayerInfoListener(const sp<IBinder>&,
+ const sp<gui::IHdrLayerInfoListener>&) override {
+ return NO_ERROR;
+ }
+
status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
const sp<IBinder>& /*stopLayerHandle*/,
const sp<IRegionSamplingListener>& /*listener*/) override {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index ffcc1cd..31027b6 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -231,6 +231,13 @@
mSensors.insert_or_assign(info.type, info);
}
+void InputDeviceInfo::addBatteryInfo(const InputDeviceBatteryInfo& info) {
+ if (mBatteries.find(info.id) != mBatteries.end()) {
+ ALOGW("Battery id %d already exists, will be replaced by new battery added.", info.id);
+ }
+ mBatteries.insert_or_assign(info.id, info);
+}
+
void InputDeviceInfo::addLightInfo(const InputDeviceLightInfo& info) {
if (mLights.find(info.id) != mLights.end()) {
ALOGW("Light id %d already exists, will be replaced by new light added.", info.id);
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 06a1722..cd7a86b 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -73,6 +73,7 @@
bool cleanupPostRender(CleanupMode mode) override;
int getContextPriority() override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
+ void onPrimaryDisplaySizeChanged(ui::Size size) override {}
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
// Creates an output image for rendering to
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 7c51f1b..a69d1f0 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -153,6 +153,10 @@
virtual bool supportsProtectedContent() const = 0;
virtual bool useProtectedContext(bool useProtectedContext) = 0;
+ // Notify RenderEngine of changes to the dimensions of the primary display
+ // so that it can configure its internal caches accordingly.
+ virtual void onPrimaryDisplaySizeChanged(ui::Size size) = 0;
+
// Renders layers for a particular display via GPU composition. This method
// should be called for every display that needs to be rendered via the GPU.
// @param display The display-wide settings that should be applied prior to
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 5f75b81..228553d 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -55,6 +55,7 @@
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
MOCK_METHOD0(supportsBackgroundBlur, bool());
+ MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size));
};
} // namespace mock
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c7001b9..0798562 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -294,12 +294,13 @@
mPlaceholderSurface(placeholder),
mProtectedEGLContext(protectedContext),
mProtectedPlaceholderSurface(protectedPlaceholder),
+ mDefaultPixelFormat(static_cast<PixelFormat>(args.pixelFormat)),
mUseColorManagement(args.useColorManagement) {
sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
LOG_ALWAYS_FATAL_IF(!glInterface.get());
GrContextOptions options;
- options.fPreferExternalImagesOverES3 = true;
+ options.fDisableDriverCorrectnessWorkarounds = true;
options.fDisableDistanceFieldPaths = true;
options.fPersistentCache = &mSkSLCacheMonitor;
mGrContext = GrDirectContext::MakeGL(glInterface, options);
@@ -1186,6 +1187,27 @@
return value;
}
+void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) {
+ // This cache multiplier was selected based on review of cache sizes relative
+ // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
+ // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
+ // conservative default based on that analysis.
+ const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat);
+ const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER;
+
+ // start by resizing the current context
+ auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext;
+ grContext->setResourceCacheLimit(maxResourceBytes);
+
+ // if it is possible to switch contexts then we will resize the other context
+ if (useProtectedContext(!mInProtectedContext)) {
+ grContext = mInProtectedContext ? mProtectedGrContext : mGrContext;
+ grContext->setResourceCacheLimit(maxResourceBytes);
+ // reset back to the initial context that was active when this method was called
+ useProtectedContext(!mInProtectedContext);
+ }
+}
+
void SkiaGLRenderEngine::dump(std::string& result) {
const gl::GLExtensions& extensions = gl::GLExtensions::getInstance();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 7605df9..25557f1 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -65,6 +65,7 @@
bool useProtectedContext(bool useProtectedContext) override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
void assertShadersCompiled(int numShaders) override;
+ void onPrimaryDisplaySizeChanged(ui::Size size) override;
protected:
void dump(std::string& result) override;
@@ -109,6 +110,7 @@
EGLSurface mProtectedPlaceholderSurface;
BlurFilter* mBlurFilter = nullptr;
+ const PixelFormat mDefaultPixelFormat;
const bool mUseColorManagement;
// Cache of GL textures that we'll store per GraphicBuffer ID
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 6a91c7c..783e37f 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -332,6 +332,21 @@
return resultFuture.get();
}
+void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) {
+ std::promise<void> resultPromise;
+ std::future<void> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, size](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged");
+ instance.onPrimaryDisplaySizeChanged(size);
+ resultPromise.set_value();
+ });
+ }
+ mCondition.notify_one();
+ resultFuture.wait();
+}
+
} // namespace threaded
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 7694328..117257a 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -66,6 +66,7 @@
void cleanFramebufferCache() override;
int getContextPriority() override;
bool supportsBackgroundBlur() override;
+ void onPrimaryDisplaySizeChanged(ui::Size size) override;
private:
void threadMain(CreateInstanceFactory factory);
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 1af70a4..7468894 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -24,6 +24,7 @@
cc_library_headers {
name: "libinputreader_headers",
export_include_dirs: [
+ "controller",
"include",
"mapper",
"mapper/accumulator",
@@ -35,17 +36,16 @@
srcs: [
"EventHub.cpp",
"InputDevice.cpp",
+ "controller/InputController.cpp",
"mapper/accumulator/CursorButtonAccumulator.cpp",
"mapper/accumulator/CursorScrollAccumulator.cpp",
"mapper/accumulator/SingleTouchMotionAccumulator.cpp",
"mapper/accumulator/TouchButtonAccumulator.cpp",
- "mapper/BatteryInputMapper.cpp",
"mapper/CursorInputMapper.cpp",
"mapper/ExternalStylusInputMapper.cpp",
"mapper/InputMapper.cpp",
"mapper/JoystickInputMapper.cpp",
"mapper/KeyboardInputMapper.cpp",
- "mapper/LightInputMapper.cpp",
"mapper/MultiTouchInputMapper.cpp",
"mapper/RotaryEncoderInputMapper.cpp",
"mapper/SensorInputMapper.cpp",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 07011f5..045d24c 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -70,6 +70,20 @@
static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
+// 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 =
+ {{"capacity", InputBatteryClass::CAPACITY},
+ {"capacity_level", InputBatteryClass::CAPACITY_LEVEL},
+ {"status", InputBatteryClass::STATUS}};
+
+// Mapping for input battery class node names lookup.
+// https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
+static const std::unordered_map<InputBatteryClass, std::string> BATTERY_NODES =
+ {{InputBatteryClass::CAPACITY, "capacity"},
+ {InputBatteryClass::CAPACITY_LEVEL, "capacity_level"},
+ {InputBatteryClass::STATUS, "status"}};
+
// must be kept in sync with definitions in kernel /drivers/power/supply/power_supply_sysfs.c
static const std::unordered_map<std::string, int32_t> BATTERY_STATUS =
{{"Unknown", BATTERY_STATUS_UNKNOWN},
@@ -349,7 +363,7 @@
virtualKeyMap(nullptr),
ffEffectPlaying(false),
ffEffectId(-1),
- nextLightId(0),
+ miscDevice(nullptr),
controllerNumber(0),
enabled(true),
isVirtual(fd < 0) {}
@@ -540,32 +554,36 @@
}
// Check the sysfs path for any input device batteries, returns true if battery found.
-bool EventHub::Device::configureBatteryLocked() {
- if (!sysfsRootPath.has_value()) {
- return false;
+bool EventHub::MiscDevice::configureBatteryLocked() {
+ nextBatteryId = 0;
+ // Check if device has any battery.
+ const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::POWER_SUPPLY);
+ for (const auto& nodePath : paths) {
+ RawBatteryInfo info;
+ info.id = ++nextBatteryId;
+ info.path = nodePath;
+ info.name = nodePath.filename();
+
+ // Scan the path for all the files
+ // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
+ const auto& files = allFilesInPath(nodePath);
+ for (const auto& file : files) {
+ const auto it = BATTERY_CLASSES.find(file.filename().string());
+ if (it != BATTERY_CLASSES.end()) {
+ info.flags |= it->second;
+ }
+ }
+ batteryInfos.insert_or_assign(info.id, info);
+ ALOGD("configureBatteryLocked rawBatteryId %d name %s", info.id, info.name.c_str());
}
- // Check if device has any batteries.
- std::vector<std::filesystem::path> batteryPaths =
- findSysfsNodes(sysfsRootPath.value(), SysfsClass::POWER_SUPPLY);
- // We only support single battery for an input device, if multiple batteries exist only the
- // first one is supported.
- if (batteryPaths.empty()) {
- // Set path to be empty
- sysfsBatteryPath = std::nullopt;
- return false;
- }
- // If a battery exists
- sysfsBatteryPath = batteryPaths[0];
- return true;
+ return !batteryInfos.empty();
}
// Check the sysfs path for any input device lights, returns true if lights found.
-bool EventHub::Device::configureLightsLocked() {
- if (!sysfsRootPath.has_value()) {
- return false;
- }
+bool EventHub::MiscDevice::configureLightsLocked() {
+ nextLightId = 0;
// Check if device has any lights.
- const auto& paths = findSysfsNodes(sysfsRootPath.value(), SysfsClass::LEDS);
+ const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::LEDS);
for (const auto& nodePath : paths) {
RawLightInfo info;
info.id = ++nextLightId;
@@ -599,6 +617,7 @@
}
}
lightInfos.insert_or_assign(info.id, info);
+ ALOGD("configureLightsLocked rawLightId %d name %s", info.id, info.name.c_str());
}
return !lightInfos.empty();
}
@@ -963,42 +982,92 @@
return Errorf("Device not found or device has no key layout.");
}
+// Gets the battery info map from battery ID to RawBatteryInfo of the miscellaneous device
+// associated with the device ID. Returns an empty map if no miscellaneous device found.
+const std::unordered_map<int32_t, RawBatteryInfo>& EventHub::getBatteryInfoLocked(
+ int32_t deviceId) const {
+ static const std::unordered_map<int32_t, RawBatteryInfo> EMPTY_BATTERY_INFO = {};
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr) {
+ return EMPTY_BATTERY_INFO;
+ }
+ auto it = mMiscDevices.find(device->identifier.descriptor);
+ if (it == mMiscDevices.end()) {
+ return EMPTY_BATTERY_INFO;
+ }
+ return it->second->batteryInfos;
+}
+
+const std::vector<int32_t> EventHub::getRawBatteryIds(int32_t deviceId) {
+ std::scoped_lock _l(mLock);
+ std::vector<int32_t> batteryIds;
+
+ for (const auto [id, info] : getBatteryInfoLocked(deviceId)) {
+ batteryIds.push_back(id);
+ }
+
+ return batteryIds;
+}
+
+std::optional<RawBatteryInfo> EventHub::getRawBatteryInfo(int32_t deviceId, int32_t batteryId) {
+ std::scoped_lock _l(mLock);
+
+ const auto infos = getBatteryInfoLocked(deviceId);
+
+ auto it = infos.find(batteryId);
+ if (it != infos.end()) {
+ return it->second;
+ }
+
+ return std::nullopt;
+}
+
+// Gets the light info map from light ID to RawLightInfo of the miscellaneous device associated
+// with the deivice ID. Returns an empty map if no miscellaneous device found.
+const std::unordered_map<int32_t, RawLightInfo>& EventHub::getLightInfoLocked(
+ int32_t deviceId) const {
+ static const std::unordered_map<int32_t, RawLightInfo> EMPTY_LIGHT_INFO = {};
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr) {
+ return EMPTY_LIGHT_INFO;
+ }
+ auto it = mMiscDevices.find(device->identifier.descriptor);
+ if (it == mMiscDevices.end()) {
+ return EMPTY_LIGHT_INFO;
+ }
+ return it->second->lightInfos;
+}
+
const std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) {
std::scoped_lock _l(mLock);
- Device* device = getDeviceLocked(deviceId);
std::vector<int32_t> lightIds;
- if (device != nullptr) {
- for (const auto [id, info] : device->lightInfos) {
- lightIds.push_back(id);
- }
+ for (const auto [id, info] : getLightInfoLocked(deviceId)) {
+ lightIds.push_back(id);
}
+
return lightIds;
}
std::optional<RawLightInfo> EventHub::getRawLightInfo(int32_t deviceId, int32_t lightId) {
std::scoped_lock _l(mLock);
- Device* device = getDeviceLocked(deviceId);
- if (device != nullptr) {
- auto it = device->lightInfos.find(lightId);
- if (it != device->lightInfos.end()) {
- return it->second;
- }
+ const auto infos = getLightInfoLocked(deviceId);
+
+ auto it = infos.find(lightId);
+ if (it != infos.end()) {
+ return it->second;
}
+
return std::nullopt;
}
std::optional<int32_t> EventHub::getLightBrightness(int32_t deviceId, int32_t lightId) {
std::scoped_lock _l(mLock);
- Device* device = getDeviceLocked(deviceId);
- if (device == nullptr) {
- return std::nullopt;
- }
-
- auto it = device->lightInfos.find(lightId);
- if (it == device->lightInfos.end()) {
+ const auto infos = getLightInfoLocked(deviceId);
+ auto it = infos.find(lightId);
+ if (it == infos.end()) {
return std::nullopt;
}
std::string buffer;
@@ -1013,13 +1082,9 @@
int32_t deviceId, int32_t lightId) {
std::scoped_lock _l(mLock);
- Device* device = getDeviceLocked(deviceId);
- if (device == nullptr) {
- return std::nullopt;
- }
-
- auto lightIt = device->lightInfos.find(lightId);
- if (lightIt == device->lightInfos.end()) {
+ const auto infos = getLightInfoLocked(deviceId);
+ auto lightIt = infos.find(lightId);
+ if (lightIt == infos.end()) {
return std::nullopt;
}
@@ -1056,14 +1121,10 @@
void EventHub::setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) {
std::scoped_lock _l(mLock);
- Device* device = getDeviceLocked(deviceId);
- if (device == nullptr) {
- ALOGE("Device Id %d does not exist", deviceId);
- return;
- }
- auto lightIt = device->lightInfos.find(lightId);
- if (lightIt == device->lightInfos.end()) {
- ALOGE("Light Id %d does not exist.", lightId);
+ const auto infos = getLightInfoLocked(deviceId);
+ auto lightIt = infos.find(lightId);
+ if (lightIt == infos.end()) {
+ ALOGE("%s lightId %d not found ", __func__, lightId);
return;
}
@@ -1078,13 +1139,9 @@
std::unordered_map<LightColor, int32_t> intensities) {
std::scoped_lock _l(mLock);
- Device* device = getDeviceLocked(deviceId);
- if (device == nullptr) {
- ALOGE("Device Id %d does not exist", deviceId);
- return;
- }
- auto lightIt = device->lightInfos.find(lightId);
- if (lightIt == device->lightInfos.end()) {
+ const auto infos = getLightInfoLocked(deviceId);
+ auto lightIt = infos.find(lightId);
+ if (lightIt == infos.end()) {
ALOGE("Light Id %d does not exist.", lightId);
return;
}
@@ -1352,51 +1409,56 @@
return nullptr;
}
-std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId) const {
+std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId, int32_t batteryId) const {
std::scoped_lock _l(mLock);
- Device* device = getDeviceLocked(deviceId);
- std::string buffer;
- if (device == nullptr || !device->sysfsBatteryPath.has_value()) {
+ const auto infos = getBatteryInfoLocked(deviceId);
+ auto it = infos.find(batteryId);
+ if (it == infos.end()) {
return std::nullopt;
}
+ std::string buffer;
// Some devices report battery capacity as an integer through the "capacity" file
- if (base::ReadFileToString(device->sysfsBatteryPath.value() / "capacity", &buffer)) {
+ if (base::ReadFileToString(it->second.path / BATTERY_NODES.at(InputBatteryClass::CAPACITY),
+ &buffer)) {
return std::stoi(base::Trim(buffer));
}
// Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX
// These values are taken from kernel source code include/linux/power_supply.h
- if (base::ReadFileToString(device->sysfsBatteryPath.value() / "capacity_level", &buffer)) {
+ if (base::ReadFileToString(it->second.path /
+ BATTERY_NODES.at(InputBatteryClass::CAPACITY_LEVEL),
+ &buffer)) {
// Remove any white space such as trailing new line
- const auto it = BATTERY_LEVEL.find(base::Trim(buffer));
- if (it != BATTERY_LEVEL.end()) {
- return it->second;
+ const auto levelIt = BATTERY_LEVEL.find(base::Trim(buffer));
+ if (levelIt != BATTERY_LEVEL.end()) {
+ return levelIt->second;
}
}
+
return std::nullopt;
}
-std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId) const {
+std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId, int32_t batteryId) const {
std::scoped_lock _l(mLock);
- Device* device = getDeviceLocked(deviceId);
- std::string buffer;
-
- if (device == nullptr || !device->sysfsBatteryPath.has_value()) {
+ const auto infos = getBatteryInfoLocked(deviceId);
+ auto it = infos.find(batteryId);
+ if (it == infos.end()) {
return std::nullopt;
}
+ std::string buffer;
- if (!base::ReadFileToString(device->sysfsBatteryPath.value() / "status", &buffer)) {
+ if (!base::ReadFileToString(it->second.path / BATTERY_NODES.at(InputBatteryClass::STATUS),
+ &buffer)) {
ALOGE("Failed to read sysfs battery info: %s", strerror(errno));
return std::nullopt;
}
// Remove white space like trailing new line
- const auto it = BATTERY_STATUS.find(base::Trim(buffer));
-
- if (it != BATTERY_STATUS.end()) {
- return it->second;
+ const auto statusIt = BATTERY_STATUS.find(base::Trim(buffer));
+ if (statusIt != BATTERY_STATUS.end()) {
+ return statusIt->second;
}
return std::nullopt;
@@ -1879,11 +1941,24 @@
// Load the configuration file for the device.
device->loadConfigurationLocked();
- // Grab the device's sysfs path
- device->sysfsRootPath = getSysfsRootPath(devicePath.c_str());
- // find related components
- bool hasBattery = device->configureBatteryLocked();
- bool hasLights = device->configureLightsLocked();
+ bool hasBattery = false;
+ bool hasLights = false;
+ // Check the sysfs root path
+ std::optional<std::filesystem::path> sysfsRootPath = getSysfsRootPath(devicePath.c_str());
+ if (sysfsRootPath.has_value()) {
+ std::shared_ptr<MiscDevice> miscDevice;
+ auto it = mMiscDevices.find(device->identifier.descriptor);
+ if (it == mMiscDevices.end()) {
+ miscDevice = std::make_shared<MiscDevice>(sysfsRootPath.value());
+ } else {
+ miscDevice = it->second;
+ }
+ hasBattery = miscDevice->configureBatteryLocked();
+ hasLights = miscDevice->configureLightsLocked();
+
+ device->miscDevice = miscDevice;
+ mMiscDevices.insert_or_assign(device->identifier.descriptor, std::move(miscDevice));
+ }
// Figure out the kinds of events the device reports.
device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask);
@@ -2254,6 +2329,12 @@
mClosingDevices.push_back(std::move(mDevices[device.id]));
mDevices.erase(device.id);
+ // If all devices with the descriptor have been removed then the miscellaneous device should
+ // be removed too.
+ std::string descriptor = device.identifier.descriptor;
+ if (getDeviceByDescriptorLocked(descriptor) == nullptr) {
+ mMiscDevices.erase(descriptor);
+ }
}
status_t EventHub::readNotifyLocked() {
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index dd1abeb..f935c36 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -21,13 +21,12 @@
#include <input/Flags.h>
#include <algorithm>
-#include "BatteryInputMapper.h"
#include "CursorInputMapper.h"
#include "ExternalStylusInputMapper.h"
+#include "InputController.h"
#include "InputReaderContext.h"
#include "JoystickInputMapper.h"
#include "KeyboardInputMapper.h"
-#include "LightInputMapper.h"
#include "MultiTouchInputMapper.h"
#include "RotaryEncoderInputMapper.h"
#include "SensorInputMapper.h"
@@ -131,6 +130,9 @@
}
for_each_mapper([&dump](InputMapper& mapper) { mapper.dump(dump); });
+ if (mController) {
+ mController->dump(dump);
+ }
}
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
@@ -162,22 +164,10 @@
mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
}
- // Battery-like devices. Only one battery mapper for each EventHub device.
- if (classes.test(InputDeviceClass::BATTERY)) {
- InputDeviceInfo deviceInfo;
- getDeviceInfo(&deviceInfo);
- if (!deviceInfo.hasBattery()) {
- mappers.push_back(std::make_unique<BatteryInputMapper>(*contextPtr));
- }
- }
-
- // Light-containing devices. Only one light mapper for each EventHub device.
- if (classes.test(InputDeviceClass::LIGHT)) {
- InputDeviceInfo deviceInfo;
- getDeviceInfo(&deviceInfo);
- if (deviceInfo.getLightIds().empty()) {
- mappers.push_back(std::make_unique<LightInputMapper>(*contextPtr));
- }
+ // Battery-like devices or light-containing devices.
+ // InputController will be created with associated EventHub device.
+ if (classes.test(InputDeviceClass::BATTERY) || classes.test(InputDeviceClass::LIGHT)) {
+ mController = std::make_unique<InputController>(*contextPtr);
}
// Keyboard-like devices.
@@ -409,6 +399,10 @@
mHasMic);
for_each_mapper(
[outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); });
+
+ if (mController) {
+ mController->populateDeviceInfo(outDeviceInfo);
+ }
}
int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
@@ -510,39 +504,30 @@
for_each_mapper([when, readTime](InputMapper& mapper) { mapper.cancelTouch(when, readTime); });
}
+// TODO b/180733860 support multiple battery in API and remove this.
+constexpr int32_t DEFAULT_BATTERY_ID = 1;
std::optional<int32_t> InputDevice::getBatteryCapacity() {
- return first_in_mappers<int32_t>(
- [](InputMapper& mapper) { return mapper.getBatteryCapacity(); });
+ return mController ? mController->getBatteryCapacity(DEFAULT_BATTERY_ID) : std::nullopt;
}
std::optional<int32_t> InputDevice::getBatteryStatus() {
- return first_in_mappers<int32_t>([](InputMapper& mapper) { return mapper.getBatteryStatus(); });
+ return mController ? mController->getBatteryStatus(DEFAULT_BATTERY_ID) : std::nullopt;
}
bool InputDevice::setLightColor(int32_t lightId, int32_t color) {
- bool success = true;
- for_each_mapper([&success, lightId, color](InputMapper& mapper) {
- success &= mapper.setLightColor(lightId, color);
- });
- return success;
+ return mController ? mController->setLightColor(lightId, color) : false;
}
bool InputDevice::setLightPlayerId(int32_t lightId, int32_t playerId) {
- bool success = true;
- for_each_mapper([&success, lightId, playerId](InputMapper& mapper) {
- success &= mapper.setLightPlayerId(lightId, playerId);
- });
- return success;
+ return mController ? mController->setLightPlayerId(lightId, playerId) : false;
}
std::optional<int32_t> InputDevice::getLightColor(int32_t lightId) {
- return first_in_mappers<int32_t>(
- [lightId](InputMapper& mapper) { return mapper.getLightColor(lightId); });
+ return mController ? mController->getLightColor(lightId) : std::nullopt;
}
std::optional<int32_t> InputDevice::getLightPlayerId(int32_t lightId) {
- return first_in_mappers<int32_t>(
- [lightId](InputMapper& mapper) { return mapper.getLightPlayerId(lightId); });
+ return mController ? mController->getLightPlayerId(lightId) : std::nullopt;
}
int32_t InputDevice::getMetaState() {
diff --git a/services/inputflinger/reader/controller/InputController.cpp b/services/inputflinger/reader/controller/InputController.cpp
new file mode 100644
index 0000000..45266fb
--- /dev/null
+++ b/services/inputflinger/reader/controller/InputController.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <locale>
+#include <regex>
+
+#include "../Macros.h"
+
+#include "InputController.h"
+#include "input/NamedEnum.h"
+
+// Log detailed debug messages about input device lights.
+static constexpr bool DEBUG_LIGHT_DETAILS = false;
+
+namespace android {
+
+static inline int32_t getAlpha(int32_t color) {
+ return (color >> 24) & 0xff;
+}
+
+static inline int32_t getRed(int32_t color) {
+ return (color >> 16) & 0xff;
+}
+
+static inline int32_t getGreen(int32_t color) {
+ return (color >> 8) & 0xff;
+}
+
+static inline int32_t getBlue(int32_t color) {
+ return color & 0xff;
+}
+
+static inline int32_t toArgb(int32_t brightness, int32_t red, int32_t green, int32_t blue) {
+ return (brightness & 0xff) << 24 | (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff);
+}
+
+/**
+ * Input controller owned by InputReader device, implements the native API for querying input
+ * lights, getting and setting the lights brightness and color, by interacting with EventHub
+ * devices.
+ */
+InputController::InputController(InputDeviceContext& deviceContext)
+ : mDeviceContext(deviceContext) {
+ configureBattries();
+ configureLights();
+}
+
+InputController::~InputController() {}
+
+std::optional<std::int32_t> InputController::Light::getRawLightBrightness(int32_t rawLightId) {
+ std::optional<RawLightInfo> rawInfoOpt = context.getRawLightInfo(rawLightId);
+ if (!rawInfoOpt.has_value()) {
+ return std::nullopt;
+ }
+ std::optional<int32_t> brightnessOpt = context.getLightBrightness(rawLightId);
+ if (!brightnessOpt.has_value()) {
+ return std::nullopt;
+ }
+ int brightness = brightnessOpt.value();
+
+ // 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;
+ // Scale the returned brightness in [0, rawMaxBrightness] to [0, 255]
+ if (rawMaxBrightness != MAX_BRIGHTNESS) {
+ brightness = brightness * ratio;
+ }
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("getRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
+ brightness, ratio);
+ }
+ return brightness;
+}
+
+void InputController::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) {
+ std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId);
+ if (!rawInfo.has_value()) {
+ return;
+ }
+ // 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;
+ // Scale the requested brightness in [0, 255] to [0, rawMaxBrightness]
+ if (rawMaxBrightness != MAX_BRIGHTNESS) {
+ brightness = ceil(brightness / ratio);
+ }
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("setRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
+ brightness, ratio);
+ }
+ context.setLightBrightness(rawLightId, brightness);
+}
+
+bool InputController::SingleLight::setLightColor(int32_t color) {
+ int32_t brightness = getAlpha(color);
+ setRawLightBrightness(rawId, brightness);
+
+ return true;
+}
+
+bool InputController::RgbLight::setLightColor(int32_t color) {
+ // Compose color value as per:
+ // https://developer.android.com/reference/android/graphics/Color?hl=en
+ // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
+ // The alpha component is used to scale the R,G,B leds brightness, with the ratio to
+ // MAX_BRIGHTNESS.
+ brightness = getAlpha(color);
+ int32_t red = 0;
+ int32_t green = 0;
+ int32_t blue = 0;
+ if (brightness > 0) {
+ float ratio = MAX_BRIGHTNESS / brightness;
+ red = ceil(getRed(color) / ratio);
+ green = ceil(getGreen(color) / ratio);
+ blue = ceil(getBlue(color) / ratio);
+ }
+ setRawLightBrightness(rawRgbIds.at(LightColor::RED), red);
+ setRawLightBrightness(rawRgbIds.at(LightColor::GREEN), green);
+ setRawLightBrightness(rawRgbIds.at(LightColor::BLUE), blue);
+ if (rawGlobalId.has_value()) {
+ setRawLightBrightness(rawGlobalId.value(), brightness);
+ }
+
+ return true;
+}
+
+bool InputController::MultiColorLight::setLightColor(int32_t color) {
+ std::unordered_map<LightColor, int32_t> intensities;
+ intensities.emplace(LightColor::RED, getRed(color));
+ intensities.emplace(LightColor::GREEN, getGreen(color));
+ intensities.emplace(LightColor::BLUE, getBlue(color));
+
+ context.setLightIntensities(rawId, intensities);
+ setRawLightBrightness(rawId, getAlpha(color));
+ return true;
+}
+
+std::optional<int32_t> InputController::SingleLight::getLightColor() {
+ std::optional<int32_t> brightness = getRawLightBrightness(rawId);
+ if (!brightness.has_value()) {
+ return std::nullopt;
+ }
+
+ return toArgb(brightness.value(), 0 /* red */, 0 /* green */, 0 /* blue */);
+}
+
+std::optional<int32_t> InputController::RgbLight::getLightColor() {
+ // If the Alpha component is zero, then return color 0.
+ if (brightness == 0) {
+ return 0;
+ }
+ // Compose color value as per:
+ // https://developer.android.com/reference/android/graphics/Color?hl=en
+ // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
+ std::optional<int32_t> redOr = getRawLightBrightness(rawRgbIds.at(LightColor::RED));
+ std::optional<int32_t> greenOr = getRawLightBrightness(rawRgbIds.at(LightColor::GREEN));
+ std::optional<int32_t> blueOr = getRawLightBrightness(rawRgbIds.at(LightColor::BLUE));
+ // If we can't get brightness for any of the RGB light
+ if (!redOr.has_value() || !greenOr.has_value() || !blueOr.has_value()) {
+ return std::nullopt;
+ }
+
+ // Compose the ARGB format color. As the R,G,B color led brightness is scaled by Alpha
+ // value, scale it back to return the nominal color value.
+ float ratio = MAX_BRIGHTNESS / brightness;
+ int32_t red = round(redOr.value() * ratio);
+ int32_t green = round(greenOr.value() * ratio);
+ int32_t blue = round(blueOr.value() * ratio);
+
+ if (red > MAX_BRIGHTNESS || green > MAX_BRIGHTNESS || blue > MAX_BRIGHTNESS) {
+ // Previously stored brightness isn't valid for current LED values, so just reset to max
+ // brightness since an app couldn't have provided these values in the first place.
+ red = redOr.value();
+ green = greenOr.value();
+ blue = blueOr.value();
+ brightness = MAX_BRIGHTNESS;
+ }
+
+ return toArgb(brightness, red, green, blue);
+}
+
+std::optional<int32_t> InputController::MultiColorLight::getLightColor() {
+ auto ret = context.getLightIntensities(rawId);
+ if (!ret.has_value()) {
+ return std::nullopt;
+ }
+ std::unordered_map<LightColor, int32_t> intensities = ret.value();
+ // Get red, green, blue colors
+ int32_t color = toArgb(0 /* brightness */, intensities.at(LightColor::RED) /* red */,
+ intensities.at(LightColor::GREEN) /* green */,
+ intensities.at(LightColor::BLUE) /* blue */);
+ // Get brightness
+ std::optional<int32_t> brightness = getRawLightBrightness(rawId);
+ if (brightness.has_value()) {
+ return toArgb(brightness.value() /* A */, 0, 0, 0) | color;
+ }
+ return std::nullopt;
+}
+
+bool InputController::PlayerIdLight::setLightPlayerId(int32_t playerId) {
+ if (rawLightIds.find(playerId) == rawLightIds.end()) {
+ return false;
+ }
+ for (const auto& [id, rawId] : rawLightIds) {
+ if (playerId == id) {
+ setRawLightBrightness(rawId, MAX_BRIGHTNESS);
+ } else {
+ setRawLightBrightness(rawId, 0);
+ }
+ }
+ return true;
+}
+
+std::optional<int32_t> InputController::PlayerIdLight::getLightPlayerId() {
+ for (const auto& [id, rawId] : rawLightIds) {
+ std::optional<int32_t> brightness = getRawLightBrightness(rawId);
+ if (brightness.has_value() && brightness.value() > 0) {
+ return id;
+ }
+ }
+ return std::nullopt;
+}
+
+void InputController::SingleLight::dump(std::string& dump) {
+ dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
+}
+
+void InputController::PlayerIdLight::dump(std::string& dump) {
+ dump += StringPrintf(INDENT4 "PlayerId: %d\n", getLightPlayerId().value_or(-1));
+ dump += StringPrintf(INDENT4 "Raw Player ID LEDs:");
+ for (const auto& [id, rawId] : rawLightIds) {
+ dump += StringPrintf("id %d -> %d ", id, rawId);
+ }
+ dump += "\n";
+}
+
+void InputController::RgbLight::dump(std::string& dump) {
+ dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
+ dump += StringPrintf(INDENT4 "Raw RGB LEDs: [%d, %d, %d] ", rawRgbIds.at(LightColor::RED),
+ rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
+ if (rawGlobalId.has_value()) {
+ dump += StringPrintf(INDENT4 "Raw Global LED: [%d] ", rawGlobalId.value());
+ }
+ dump += "\n";
+}
+
+void InputController::MultiColorLight::dump(std::string& dump) {
+ dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
+}
+
+void InputController::populateDeviceInfo(InputDeviceInfo* deviceInfo) {
+ // TODO: b/180733860 Remove this after enabling multi-battery
+ if (!mBatteries.empty()) {
+ deviceInfo->setHasBattery(true);
+ }
+
+ for (const auto& [batteryId, battery] : mBatteries) {
+ InputDeviceBatteryInfo batteryInfo(battery->name, battery->id);
+ deviceInfo->addBatteryInfo(batteryInfo);
+ }
+
+ 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 */);
+ deviceInfo->addLightInfo(lightInfo);
+ }
+}
+
+void InputController::dump(std::string& dump) {
+ dump += INDENT2 "Input Controller:\n";
+ if (!mLights.empty()) {
+ dump += INDENT3 "Lights:\n";
+ for (const auto& [lightId, light] : mLights) {
+ dump += StringPrintf(INDENT4 "Id: %d", lightId);
+ dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str());
+ dump += StringPrintf(INDENT4 "Type: %s", NamedEnum::string(light->type).c_str());
+ light->dump(dump);
+ }
+ }
+ // Dump raw lights
+ dump += INDENT3 "RawLights:\n";
+ dump += INDENT4 "Id:\t Name:\t Flags:\t Max brightness:\t Brightness\n";
+ const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
+ // Map from raw light id to raw light info
+ std::unordered_map<int32_t, RawLightInfo> rawInfos;
+ for (const auto& rawId : rawLightIds) {
+ std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
+ if (!rawInfo.has_value()) {
+ continue;
+ }
+ dump += StringPrintf(INDENT4 "%d", rawId);
+ dump += StringPrintf(INDENT4 "%s", rawInfo->name.c_str());
+ dump += StringPrintf(INDENT4 "%s", rawInfo->flags.string().c_str());
+ dump += StringPrintf(INDENT4 "%d", rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS));
+ dump += StringPrintf(INDENT4 "%d\n",
+ getDeviceContext().getLightBrightness(rawId).value_or(-1));
+ }
+
+ if (!mBatteries.empty()) {
+ dump += INDENT3 "Batteries:\n";
+ for (const auto& [batteryId, battery] : mBatteries) {
+ dump += StringPrintf(INDENT4 "Id: %d", batteryId);
+ dump += StringPrintf(INDENT4 "Name: %s", battery->name.c_str());
+ dump += getBatteryCapacity(batteryId).has_value()
+ ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity(batteryId).value())
+ : StringPrintf(INDENT3 "Capacity: Unknown");
+
+ std::string status;
+ switch (getBatteryStatus(batteryId).value_or(BATTERY_STATUS_UNKNOWN)) {
+ case BATTERY_STATUS_CHARGING:
+ status = "Charging";
+ break;
+ case BATTERY_STATUS_DISCHARGING:
+ status = "Discharging";
+ break;
+ case BATTERY_STATUS_NOT_CHARGING:
+ status = "Not charging";
+ break;
+ case BATTERY_STATUS_FULL:
+ status = "Full";
+ break;
+ default:
+ status = "Unknown";
+ }
+ dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str());
+ }
+ }
+}
+
+void InputController::configureBattries() {
+ // Check raw batteries
+ const std::vector<int32_t> rawBatteryIds = getDeviceContext().getRawBatteryIds();
+
+ for (const auto& rawId : rawBatteryIds) {
+ std::optional<RawBatteryInfo> rawInfo = getDeviceContext().getRawBatteryInfo(rawId);
+ if (!rawInfo.has_value()) {
+ continue;
+ }
+ std::unique_ptr<Battery> battery =
+ std::make_unique<Battery>(getDeviceContext(), rawInfo->name, rawInfo->id);
+ mBatteries.insert_or_assign(rawId, std::move(battery));
+ }
+}
+
+void InputController::configureLights() {
+ bool hasRedLed = false;
+ bool hasGreenLed = false;
+ bool hasBlueLed = false;
+ std::optional<int32_t> rawGlobalId = std::nullopt;
+ // Player ID light common name string
+ std::string playerIdName;
+ // Raw RGB color to raw light ID
+ std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
+ // Map from player Id to raw light Id
+ std::unordered_map<int32_t, int32_t> playerIdLightIds;
+
+ // Check raw lights
+ const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
+ // Map from raw light id to raw light info
+ std::unordered_map<int32_t, RawLightInfo> rawInfos;
+ for (const auto& rawId : rawLightIds) {
+ std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
+ if (!rawInfo.has_value()) {
+ continue;
+ }
+ rawInfos.insert_or_assign(rawId, rawInfo.value());
+ // Check if this is a group LEDs for player ID
+ std::regex lightPattern("([a-z]+)([0-9]+)");
+ std::smatch results;
+ if (std::regex_match(rawInfo->name, results, lightPattern)) {
+ std::string commonName = results[1].str();
+ int32_t playerId = std::stoi(results[2]);
+ if (playerIdLightIds.empty()) {
+ playerIdName = commonName;
+ playerIdLightIds.insert_or_assign(playerId, rawId);
+ } else {
+ // Make sure the player ID leds have common string name
+ if (playerIdName.compare(commonName) == 0 &&
+ playerIdLightIds.find(playerId) == playerIdLightIds.end()) {
+ playerIdLightIds.insert_or_assign(playerId, rawId);
+ }
+ }
+ }
+ // Check if this is an LED of RGB light
+ if (rawInfo->flags.test(InputLightClass::RED)) {
+ hasRedLed = true;
+ rawRgbIds.emplace(LightColor::RED, rawId);
+ }
+ if (rawInfo->flags.test(InputLightClass::GREEN)) {
+ hasGreenLed = true;
+ rawRgbIds.emplace(LightColor::GREEN, rawId);
+ }
+ if (rawInfo->flags.test(InputLightClass::BLUE)) {
+ hasBlueLed = true;
+ rawRgbIds.emplace(LightColor::BLUE, rawId);
+ }
+ if (rawInfo->flags.test(InputLightClass::GLOBAL)) {
+ rawGlobalId = rawId;
+ }
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("Light rawId %d name %s max %d flags %s \n", rawInfo->id, rawInfo->name.c_str(),
+ rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS), rawInfo->flags.string().c_str());
+ }
+ }
+
+ // Construct a player ID light
+ if (playerIdLightIds.size() > 1) {
+ std::unique_ptr<Light> light =
+ std::make_unique<PlayerIdLight>(getDeviceContext(), playerIdName, ++mNextId,
+ playerIdLightIds);
+ mLights.insert_or_assign(light->id, std::move(light));
+ // Remove these raw lights from raw light info as they've been used to compose a
+ // Player ID light, so we do not expose these raw lights as single lights.
+ for (const auto& [playerId, rawId] : playerIdLightIds) {
+ rawInfos.erase(rawId);
+ }
+ }
+ // Construct a RGB light for composed RGB light
+ if (hasRedLed && hasGreenLed && hasBlueLed) {
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED),
+ rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
+ }
+ std::unique_ptr<Light> light =
+ std::make_unique<RgbLight>(getDeviceContext(), ++mNextId, 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));
+ rawInfos.erase(rawRgbIds.at(LightColor::GREEN));
+ rawInfos.erase(rawRgbIds.at(LightColor::BLUE));
+ if (rawGlobalId.has_value()) {
+ rawInfos.erase(rawGlobalId.value());
+ }
+ }
+
+ // Check the rest of raw light infos
+ for (const auto& [rawId, rawInfo] : rawInfos) {
+ // 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)) {
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("Multicolor light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
+ }
+ std::unique_ptr<Light> light =
+ std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name, ++mNextId,
+ rawInfo.id);
+ mLights.insert_or_assign(light->id, std::move(light));
+ continue;
+ }
+ // Construct a single LED light
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("Single light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
+ }
+ std::unique_ptr<Light> light =
+ std::make_unique<SingleLight>(getDeviceContext(), rawInfo.name, ++mNextId,
+ rawInfo.id);
+
+ mLights.insert_or_assign(light->id, std::move(light));
+ }
+}
+
+std::optional<int32_t> InputController::getBatteryCapacity(int batteryId) {
+ return getDeviceContext().getBatteryCapacity(batteryId);
+}
+
+std::optional<int32_t> InputController::getBatteryStatus(int batteryId) {
+ return getDeviceContext().getBatteryStatus(batteryId);
+}
+
+bool InputController::setLightColor(int32_t lightId, int32_t color) {
+ auto it = mLights.find(lightId);
+ if (it == mLights.end()) {
+ return false;
+ }
+ auto& light = it->second;
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("setLightColor lightId %d type %s color 0x%x", lightId,
+ NamedEnum::string(light->type).c_str(), color);
+ }
+ return light->setLightColor(color);
+}
+
+std::optional<int32_t> InputController::getLightColor(int32_t lightId) {
+ auto it = mLights.find(lightId);
+ if (it == mLights.end()) {
+ return std::nullopt;
+ }
+ auto& light = it->second;
+ std::optional<int32_t> color = light->getLightColor();
+ if (DEBUG_LIGHT_DETAILS) {
+ ALOGD("getLightColor lightId %d type %s color 0x%x", lightId,
+ NamedEnum::string(light->type).c_str(), color.value_or(0));
+ }
+ return color;
+}
+
+bool InputController::setLightPlayerId(int32_t lightId, int32_t playerId) {
+ auto it = mLights.find(lightId);
+ if (it == mLights.end()) {
+ return false;
+ }
+ auto& light = it->second;
+ return light->setLightPlayerId(playerId);
+}
+
+std::optional<int32_t> InputController::getLightPlayerId(int32_t lightId) {
+ auto it = mLights.find(lightId);
+ if (it == mLights.end()) {
+ return std::nullopt;
+ }
+ auto& light = it->second;
+ return light->getLightPlayerId();
+}
+
+} // namespace android
diff --git a/services/inputflinger/reader/mapper/LightInputMapper.h b/services/inputflinger/reader/controller/InputController.h
similarity index 81%
rename from services/inputflinger/reader/mapper/LightInputMapper.h
rename to services/inputflinger/reader/controller/InputController.h
index 43141b8..d4222e2 100644
--- a/services/inputflinger/reader/mapper/LightInputMapper.h
+++ b/services/inputflinger/reader/controller/InputController.h
@@ -14,35 +14,49 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H
-#define _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H
+#ifndef _UI_INPUTREADER_LIGHT_CONTROLLER_H
+#define _UI_INPUTREADER_LIGHT_CONTROLLER_H
-#include "InputMapper.h"
+#include "InputControllerInterface.h"
namespace android {
-class LightInputMapper : public InputMapper {
+class InputController : public InputControllerInterface {
// Refer to https://developer.android.com/reference/kotlin/android/graphics/Color
/* Number of colors : {red, green, blue} */
static constexpr size_t COLOR_NUM = 3;
static constexpr int32_t MAX_BRIGHTNESS = 0xff;
public:
- explicit LightInputMapper(InputDeviceContext& deviceContext);
- ~LightInputMapper() override;
+ explicit InputController(InputDeviceContext& deviceContext);
+ ~InputController() override;
- uint32_t getSources() override;
void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
void dump(std::string& dump) override;
- void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override;
- void reset(nsecs_t when) override;
- void process(const RawEvent* rawEvent) override;
bool setLightColor(int32_t lightId, int32_t color) override;
bool setLightPlayerId(int32_t lightId, int32_t playerId) override;
std::optional<int32_t> getLightColor(int32_t lightId) override;
std::optional<int32_t> getLightPlayerId(int32_t lightId) override;
+ std::optional<int32_t> getBatteryCapacity(int32_t batteryId) override;
+ std::optional<int32_t> getBatteryStatus(int32_t batteryId) override;
private:
+ inline int32_t getDeviceId() { return mDeviceContext.getId(); }
+ inline InputDeviceContext& getDeviceContext() { return mDeviceContext; }
+
+ InputDeviceContext& mDeviceContext;
+ void configureLights();
+ void configureBattries();
+
+ struct Battery {
+ explicit Battery(InputDeviceContext& context, const std::string& name, int32_t id)
+ : context(context), name(name), id(id) {}
+ virtual ~Battery() {}
+ InputDeviceContext& context;
+ std::string name;
+ int32_t id;
+ };
+
struct Light {
explicit Light(InputDeviceContext& context, const std::string& name, int32_t id,
InputDeviceLightType type)
@@ -128,8 +142,11 @@
// Light map from light ID to Light
std::unordered_map<int32_t, std::unique_ptr<Light>> mLights;
+
+ // Battery map from battery ID to battery
+ std::unordered_map<int32_t, std::unique_ptr<Battery>> mBatteries;
};
} // namespace android
-#endif // _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H
+#endif // _UI_INPUTREADER_LIGHT_CONTROLLER_H
diff --git a/services/inputflinger/reader/controller/InputControllerInterface.h b/services/inputflinger/reader/controller/InputControllerInterface.h
new file mode 100644
index 0000000..504eded
--- /dev/null
+++ b/services/inputflinger/reader/controller/InputControllerInterface.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUTREADER_INPUT_CONTROLLER_H
+#define _UI_INPUTREADER_INPUT_CONTROLLER_H
+
+#include "EventHub.h"
+#include "InputDevice.h"
+#include "InputListener.h"
+#include "InputReaderContext.h"
+
+namespace android {
+
+/* An input controller manages the miscellaneous devices associated with the input device,
+ * like the sysfs based battery and light class devices.
+ *
+ */
+class InputControllerInterface {
+public:
+ InputControllerInterface() {}
+ virtual ~InputControllerInterface() {}
+
+ // Interface methods for Battery
+ virtual std::optional<int32_t> getBatteryCapacity(int32_t batteryId) = 0;
+ virtual std::optional<int32_t> getBatteryStatus(int32_t batteryId) = 0;
+
+ // Interface methods for Light
+ virtual bool setLightColor(int32_t lightId, int32_t color) = 0;
+ virtual bool setLightPlayerId(int32_t lightId, int32_t playerId) = 0;
+ virtual std::optional<int32_t> getLightColor(int32_t lightId) = 0;
+ virtual std::optional<int32_t> getLightPlayerId(int32_t lightId) = 0;
+
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) = 0;
+ virtual void dump(std::string& dump) = 0;
+};
+
+} // namespace android
+
+#endif // _UI_INPUTREADER_INPUT_CONTROLLER_H
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 2afaa85..c970c8b 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -173,6 +173,15 @@
MAX_BRIGHTNESS = 0x00000080,
};
+enum class InputBatteryClass : uint32_t {
+ /* The input device battery has capacity node. */
+ CAPACITY = 0x00000001,
+ /* The input device battery has capacity_level node. */
+ CAPACITY_LEVEL = 0x00000002,
+ /* The input device battery has status node. */
+ STATUS = 0x00000004,
+};
+
/* Describes a raw light. */
struct RawLightInfo {
int32_t id;
@@ -183,6 +192,14 @@
std::filesystem::path path;
};
+/* Describes a raw battery. */
+struct RawBatteryInfo {
+ int32_t id;
+ std::string name;
+ Flags<InputBatteryClass> flags;
+ std::filesystem::path path;
+};
+
/*
* Gets the class that owns an axis, in cases where multiple classes might claim
* the same axis for different purposes.
@@ -263,6 +280,12 @@
virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) = 0;
virtual base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId,
int32_t absCode) = 0;
+ // Raw batteries are sysfs power_supply nodes we found from the EventHub device sysfs node,
+ // containing the raw info of the sysfs node structure.
+ virtual const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) = 0;
+ virtual std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId,
+ int32_t BatteryId) = 0;
+
// Raw lights are sysfs led light nodes we found from the EventHub device sysfs node,
// containing the raw info of the sysfs node structure.
virtual const std::vector<int32_t> getRawLightIds(int32_t deviceId) = 0;
@@ -307,10 +330,11 @@
virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
/* Query battery level. */
- virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) const = 0;
+ virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId,
+ int32_t batteryId) const = 0;
/* Query battery status. */
- virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) const = 0;
+ virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId, int32_t batteryId) const = 0;
/* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
virtual void requestReopenDevices() = 0;
@@ -435,6 +459,10 @@
base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(
int32_t deviceId, int32_t absCode) override final;
+ const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) override final;
+ std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId,
+ int32_t BatteryId) override final;
+
const std::vector<int32_t> getRawLightIds(int32_t deviceId) override final;
std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override final;
@@ -485,9 +513,11 @@
void monitor() override final;
- std::optional<int32_t> getBatteryCapacity(int32_t deviceId) const override final;
+ std::optional<int32_t> getBatteryCapacity(int32_t deviceId,
+ int32_t batteryId) const override final;
- std::optional<int32_t> getBatteryStatus(int32_t deviceId) const override final;
+ std::optional<int32_t> getBatteryStatus(int32_t deviceId,
+ int32_t batteryId) const override final;
bool isDeviceEnabled(int32_t deviceId) override final;
@@ -498,6 +528,22 @@
~EventHub() override;
private:
+ struct MiscDevice {
+ // The device descriptor from evdev device the misc device associated with.
+ std::string descriptor;
+ // The sysfs root path of the misc device.
+ std::filesystem::path sysfsRootPath;
+
+ int32_t nextBatteryId;
+ int32_t nextLightId;
+ std::unordered_map<int32_t, RawBatteryInfo> batteryInfos;
+ std::unordered_map<int32_t, RawLightInfo> lightInfos;
+ explicit MiscDevice(std::filesystem::path sysfsRootPath)
+ : sysfsRootPath(sysfsRootPath), nextBatteryId(0), nextLightId(0) {}
+ bool configureBatteryLocked();
+ bool configureLightsLocked();
+ };
+
struct Device {
int fd; // may be -1 if device is closed
const int32_t id;
@@ -527,12 +573,7 @@
bool ffEffectPlaying;
int16_t ffEffectId; // initially -1
- // The paths are invalid when they're std::nullopt
- std::optional<std::filesystem::path> sysfsRootPath;
- std::optional<std::filesystem::path> sysfsBatteryPath;
- // maps from light id to light info
- std::unordered_map<int32_t, RawLightInfo> lightInfos;
- int32_t nextLightId;
+ std::shared_ptr<MiscDevice> miscDevice;
int32_t controllerNumber;
@@ -563,8 +604,6 @@
void setLedForControllerLocked();
status_t mapLed(int32_t led, int32_t* outScanCode) const;
void setLedStateLocked(int32_t led, bool on);
- bool configureBatteryLocked();
- bool configureLightsLocked();
};
/**
@@ -616,6 +655,12 @@
void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
Flags<InputDeviceClass> classes) REQUIRES(mLock);
+ const std::unordered_map<int32_t, RawBatteryInfo>& getBatteryInfoLocked(int32_t deviceId) const
+ REQUIRES(mLock);
+
+ const std::unordered_map<int32_t, RawLightInfo>& getLightInfoLocked(int32_t deviceId) const
+ REQUIRES(mLock);
+
// Protect all internal state.
mutable std::mutex mLock;
@@ -645,6 +690,11 @@
std::vector<std::unique_ptr<Device>> mOpeningDevices;
std::vector<std::unique_ptr<Device>> mClosingDevices;
+ // Map from std::string descriptor, to a shared_ptr of a miscellaneous device associated with
+ // the input device. The descriptor is the same from the EventHub device which it associates
+ // with.
+ std::unordered_map<std::string, std::shared_ptr<MiscDevice>> mMiscDevices;
+
bool mNeedToSendFinishedDeviceScan;
bool mNeedToReopenDevices;
bool mNeedToScanDevices;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 863cd41..5d56f5a 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -33,6 +33,8 @@
namespace android {
+class InputController;
+class InputControllerInterface;
class InputDeviceContext;
class InputMapper;
@@ -131,6 +133,20 @@
return *mapper;
}
+ // construct and add a controller to the input device
+ template <class T>
+ T& addController(int32_t eventHubId) {
+ // ensure a device entry exists for this eventHubId
+ addEventHubDevice(eventHubId, false);
+
+ // create controller
+ auto& devicePair = mDevices[eventHubId];
+ auto& deviceContext = devicePair.first;
+
+ mController = std::make_unique<T>(*deviceContext);
+ return *(reinterpret_cast<T*>(mController.get()));
+ }
+
private:
InputReaderContext* mContext;
int32_t mId;
@@ -143,7 +159,10 @@
// map from eventHubId to device context and mappers
using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>;
+ // Map from EventHub ID to pair of device context and vector of mapper.
std::unordered_map<int32_t, DevicePair> mDevices;
+ // Misc devices controller for lights, battery, etc.
+ std::unique_ptr<InputControllerInterface> mController;
uint32_t mSources;
bool mIsExternal;
@@ -319,11 +338,21 @@
inline std::vector<int32_t> getVibratorIds() { return mEventHub->getVibratorIds(mId); }
- inline std::optional<int32_t> getBatteryCapacity() {
- return mEventHub->getBatteryCapacity(mId);
+ inline const std::vector<int32_t> getRawBatteryIds() {
+ return mEventHub->getRawBatteryIds(mId);
}
- inline std::optional<int32_t> getBatteryStatus() { return mEventHub->getBatteryStatus(mId); }
+ inline std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t batteryId) {
+ return mEventHub->getRawBatteryInfo(mId, batteryId);
+ }
+
+ inline std::optional<int32_t> getBatteryCapacity(int32_t batteryId) {
+ return mEventHub->getBatteryCapacity(mId, batteryId);
+ }
+
+ inline std::optional<int32_t> getBatteryStatus(int32_t batteryId) {
+ return mEventHub->getBatteryStatus(mId, batteryId);
+ }
inline bool hasAbsoluteAxis(int32_t code) const {
RawAbsoluteAxisInfo info;
diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.cpp b/services/inputflinger/reader/mapper/BatteryInputMapper.cpp
deleted file mode 100644
index e4fb3a6..0000000
--- a/services/inputflinger/reader/mapper/BatteryInputMapper.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "../Macros.h"
-
-#include "BatteryInputMapper.h"
-
-namespace android {
-
-BatteryInputMapper::BatteryInputMapper(InputDeviceContext& deviceContext)
- : InputMapper(deviceContext) {}
-
-uint32_t BatteryInputMapper::getSources() {
- return AINPUT_SOURCE_UNKNOWN;
-}
-
-void BatteryInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
- InputMapper::populateDeviceInfo(info);
-
- info->setHasBattery(true);
-}
-
-void BatteryInputMapper::process(const RawEvent* rawEvent) {}
-
-std::optional<int32_t> BatteryInputMapper::getBatteryCapacity() {
- return getDeviceContext().getBatteryCapacity();
-}
-
-std::optional<int32_t> BatteryInputMapper::getBatteryStatus() {
- return getDeviceContext().getBatteryStatus();
-}
-
-void BatteryInputMapper::dump(std::string& dump) {
- dump += INDENT2 "Battery Input Mapper:\n";
- dump += getBatteryCapacity().has_value()
- ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity().value())
- : StringPrintf(INDENT3 "Capacity: Unknown");
-
- std::string status;
- switch (getBatteryStatus().value_or(BATTERY_STATUS_UNKNOWN)) {
- case BATTERY_STATUS_CHARGING:
- status = "Charging";
- break;
- case BATTERY_STATUS_DISCHARGING:
- status = "Discharging";
- break;
- case BATTERY_STATUS_NOT_CHARGING:
- status = "Not charging";
- break;
- case BATTERY_STATUS_FULL:
- status = "Full";
- break;
- default:
- status = "Unknown";
- }
- dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str());
-}
-
-} // namespace android
diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.h b/services/inputflinger/reader/mapper/BatteryInputMapper.h
deleted file mode 100644
index 4fe373e..0000000
--- a/services/inputflinger/reader/mapper/BatteryInputMapper.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H
-#define _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H
-
-#include "InputMapper.h"
-
-namespace android {
-
-class BatteryInputMapper : public InputMapper {
-public:
- explicit BatteryInputMapper(InputDeviceContext& deviceContext);
- virtual ~BatteryInputMapper(){};
-
- uint32_t getSources() override;
- void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
- void process(const RawEvent* rawEvent) override;
-
- std::optional<int32_t> getBatteryCapacity() override;
- std::optional<int32_t> getBatteryStatus() override;
-
- void dump(std::string& dump) override;
-};
-
-} // namespace android
-
-#endif // _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H
diff --git a/services/inputflinger/reader/mapper/LightInputMapper.cpp b/services/inputflinger/reader/mapper/LightInputMapper.cpp
deleted file mode 100644
index be1f722..0000000
--- a/services/inputflinger/reader/mapper/LightInputMapper.cpp
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <locale>
-#include <regex>
-
-#include "../Macros.h"
-
-#include "LightInputMapper.h"
-#include "input/NamedEnum.h"
-
-// Log detailed debug messages about input device lights.
-static constexpr bool DEBUG_LIGHT_DETAILS = false;
-
-namespace android {
-
-static inline int32_t getAlpha(int32_t color) {
- return (color >> 24) & 0xff;
-}
-
-static inline int32_t getRed(int32_t color) {
- return (color >> 16) & 0xff;
-}
-
-static inline int32_t getGreen(int32_t color) {
- return (color >> 8) & 0xff;
-}
-
-static inline int32_t getBlue(int32_t color) {
- return color & 0xff;
-}
-
-static inline int32_t toArgb(int32_t brightness, int32_t red, int32_t green, int32_t blue) {
- return (brightness & 0xff) << 24 | (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff);
-}
-
-/**
- * Light input mapper owned by InputReader device, implements the native API for querying input
- * lights, getting and setting the lights brightness and color, by interacting with EventHub
- * devices.
- * TODO b/180342233: Reconsider the inputflinger design to accommodate the device class
- * like lights and battery.
- */
-LightInputMapper::LightInputMapper(InputDeviceContext& deviceContext)
- : InputMapper(deviceContext) {}
-
-LightInputMapper::~LightInputMapper() {}
-
-std::optional<std::int32_t> LightInputMapper::Light::getRawLightBrightness(int32_t rawLightId) {
- std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId);
- std::optional<int32_t> ret = context.getLightBrightness(rawLightId);
- if (!rawInfo.has_value() || !ret.has_value()) {
- return std::nullopt;
- }
- int brightness = ret.value();
-
- // 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;
- // Scale the returned brightness in [0, rawMaxBrightness] to [0, 255]
- if (rawMaxBrightness != MAX_BRIGHTNESS) {
- brightness = brightness * ratio;
- }
- if (DEBUG_LIGHT_DETAILS) {
- ALOGD("getRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
- brightness, ratio);
- }
- return brightness;
-}
-
-void LightInputMapper::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) {
- std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId);
- if (!rawInfo.has_value()) {
- return;
- }
- // 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;
- // Scale the requested brightness in [0, 255] to [0, rawMaxBrightness]
- if (rawMaxBrightness != MAX_BRIGHTNESS) {
- brightness = ceil(brightness / ratio);
- }
- if (DEBUG_LIGHT_DETAILS) {
- ALOGD("setRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
- brightness, ratio);
- }
- context.setLightBrightness(rawLightId, brightness);
-}
-
-bool LightInputMapper::SingleLight::setLightColor(int32_t color) {
- int32_t brightness = getAlpha(color);
- setRawLightBrightness(rawId, brightness);
-
- return true;
-}
-
-bool LightInputMapper::RgbLight::setLightColor(int32_t color) {
- // Compose color value as per:
- // https://developer.android.com/reference/android/graphics/Color?hl=en
- // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
- // The alpha component is used to scale the R,G,B leds brightness, with the ratio to
- // MAX_BRIGHTNESS.
- brightness = getAlpha(color);
- int32_t red = 0;
- int32_t green = 0;
- int32_t blue = 0;
- if (brightness > 0) {
- float ratio = MAX_BRIGHTNESS / brightness;
- red = ceil(getRed(color) / ratio);
- green = ceil(getGreen(color) / ratio);
- blue = ceil(getBlue(color) / ratio);
- }
- setRawLightBrightness(rawRgbIds.at(LightColor::RED), red);
- setRawLightBrightness(rawRgbIds.at(LightColor::GREEN), green);
- setRawLightBrightness(rawRgbIds.at(LightColor::BLUE), blue);
- if (rawGlobalId.has_value()) {
- setRawLightBrightness(rawGlobalId.value(), brightness);
- }
-
- return true;
-}
-
-bool LightInputMapper::MultiColorLight::setLightColor(int32_t color) {
- std::unordered_map<LightColor, int32_t> intensities;
- intensities.emplace(LightColor::RED, getRed(color));
- intensities.emplace(LightColor::GREEN, getGreen(color));
- intensities.emplace(LightColor::BLUE, getBlue(color));
-
- context.setLightIntensities(rawId, intensities);
- setRawLightBrightness(rawId, getAlpha(color));
- return true;
-}
-
-std::optional<int32_t> LightInputMapper::SingleLight::getLightColor() {
- std::optional<int32_t> brightness = getRawLightBrightness(rawId);
- if (!brightness.has_value()) {
- return std::nullopt;
- }
-
- return toArgb(brightness.value(), 0 /* red */, 0 /* green */, 0 /* blue */);
-}
-
-std::optional<int32_t> LightInputMapper::RgbLight::getLightColor() {
- // If the Alpha component is zero, then return color 0.
- if (brightness == 0) {
- return 0;
- }
- // Compose color value as per:
- // https://developer.android.com/reference/android/graphics/Color?hl=en
- // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
- std::optional<int32_t> redOr = getRawLightBrightness(rawRgbIds.at(LightColor::RED));
- std::optional<int32_t> greenOr = getRawLightBrightness(rawRgbIds.at(LightColor::GREEN));
- std::optional<int32_t> blueOr = getRawLightBrightness(rawRgbIds.at(LightColor::BLUE));
- // If we can't get brightness for any of the RGB light
- if (!redOr.has_value() || !greenOr.has_value() || !blueOr.has_value()) {
- return std::nullopt;
- }
-
- // Compose the ARGB format color. As the R,G,B color led brightness is scaled by Alpha
- // value, scale it back to return the nominal color value.
- float ratio = MAX_BRIGHTNESS / brightness;
- int32_t red = round(redOr.value() * ratio);
- int32_t green = round(greenOr.value() * ratio);
- int32_t blue = round(blueOr.value() * ratio);
-
- if (red > MAX_BRIGHTNESS || green > MAX_BRIGHTNESS || blue > MAX_BRIGHTNESS) {
- // Previously stored brightness isn't valid for current LED values, so just reset to max
- // brightness since an app couldn't have provided these values in the first place.
- red = redOr.value();
- green = greenOr.value();
- blue = blueOr.value();
- brightness = MAX_BRIGHTNESS;
- }
-
- return toArgb(brightness, red, green, blue);
-}
-
-std::optional<int32_t> LightInputMapper::MultiColorLight::getLightColor() {
- auto ret = context.getLightIntensities(rawId);
- if (!ret.has_value()) {
- return std::nullopt;
- }
- std::unordered_map<LightColor, int32_t> intensities = ret.value();
- // Get red, green, blue colors
- int32_t color = toArgb(0 /* brightness */, intensities.at(LightColor::RED) /* red */,
- intensities.at(LightColor::GREEN) /* green */,
- intensities.at(LightColor::BLUE) /* blue */);
- // Get brightness
- std::optional<int32_t> brightness = getRawLightBrightness(rawId);
- if (brightness.has_value()) {
- return toArgb(brightness.value() /* A */, 0, 0, 0) | color;
- }
- return std::nullopt;
-}
-
-bool LightInputMapper::PlayerIdLight::setLightPlayerId(int32_t playerId) {
- if (rawLightIds.find(playerId) == rawLightIds.end()) {
- return false;
- }
- for (const auto& [id, rawId] : rawLightIds) {
- if (playerId == id) {
- setRawLightBrightness(rawId, MAX_BRIGHTNESS);
- } else {
- setRawLightBrightness(rawId, 0);
- }
- }
- return true;
-}
-
-std::optional<int32_t> LightInputMapper::PlayerIdLight::getLightPlayerId() {
- for (const auto& [id, rawId] : rawLightIds) {
- std::optional<int32_t> brightness = getRawLightBrightness(rawId);
- if (brightness.has_value() && brightness.value() > 0) {
- return id;
- }
- }
- return std::nullopt;
-}
-
-void LightInputMapper::SingleLight::dump(std::string& dump) {
- dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
-}
-
-void LightInputMapper::PlayerIdLight::dump(std::string& dump) {
- dump += StringPrintf(INDENT4 "PlayerId: %d\n", getLightPlayerId().value_or(-1));
- dump += StringPrintf(INDENT4 "Raw Player ID LEDs:");
- for (const auto& [id, rawId] : rawLightIds) {
- dump += StringPrintf("id %d -> %d ", id, rawId);
- }
- dump += "\n";
-}
-
-void LightInputMapper::RgbLight::dump(std::string& dump) {
- dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
- dump += StringPrintf(INDENT4 "Raw RGB LEDs: [%d, %d, %d] ", rawRgbIds.at(LightColor::RED),
- rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
- if (rawGlobalId.has_value()) {
- dump += StringPrintf(INDENT4 "Raw Global LED: [%d] ", rawGlobalId.value());
- }
- dump += "\n";
-}
-
-void LightInputMapper::MultiColorLight::dump(std::string& dump) {
- dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
-}
-
-uint32_t LightInputMapper::getSources() {
- return AINPUT_SOURCE_UNKNOWN;
-}
-
-void LightInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
- InputMapper::populateDeviceInfo(info);
-
- 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 */);
- info->addLightInfo(lightInfo);
- }
-}
-
-void LightInputMapper::dump(std::string& dump) {
- dump += INDENT2 "Light Input Mapper:\n";
- dump += INDENT3 "Lights:\n";
- for (const auto& [lightId, light] : mLights) {
- dump += StringPrintf(INDENT4 "Id: %d", lightId);
- dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str());
- dump += StringPrintf(INDENT4 "Type: %s", NamedEnum::string(light->type).c_str());
- light->dump(dump);
- }
- // Dump raw lights
- dump += INDENT3 "RawLights:\n";
- dump += INDENT4 "Id:\t Name:\t Flags:\t Max brightness:\t Brightness\n";
- const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
- // Map from raw light id to raw light info
- std::unordered_map<int32_t, RawLightInfo> rawInfos;
- for (const auto& rawId : rawLightIds) {
- std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
- if (!rawInfo.has_value()) {
- continue;
- }
- dump += StringPrintf(INDENT4 "%d", rawId);
- dump += StringPrintf(INDENT4 "%s", rawInfo->name.c_str());
- dump += StringPrintf(INDENT4 "%s", rawInfo->flags.string().c_str());
- dump += StringPrintf(INDENT4 "%d", rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS));
- dump += StringPrintf(INDENT4 "%d\n",
- getDeviceContext().getLightBrightness(rawId).value_or(-1));
- }
-}
-
-void LightInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) {
- InputMapper::configure(when, config, changes);
-
- if (!changes) { // first time only
- bool hasRedLed = false;
- bool hasGreenLed = false;
- bool hasBlueLed = false;
- std::optional<int32_t> rawGlobalId = std::nullopt;
- // Player ID light common name string
- std::string playerIdName;
- // Raw RGB color to raw light ID
- std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
- // Map from player Id to raw light Id
- std::unordered_map<int32_t, int32_t> playerIdLightIds;
- mLights.clear();
-
- // Check raw lights
- const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
- // Map from raw light id to raw light info
- std::unordered_map<int32_t, RawLightInfo> rawInfos;
- for (const auto& rawId : rawLightIds) {
- std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
- if (!rawInfo.has_value()) {
- continue;
- }
- rawInfos.insert_or_assign(rawId, rawInfo.value());
- // Check if this is a group LEDs for player ID
- std::regex lightPattern("([a-z]+)([0-9]+)");
- std::smatch results;
- if (std::regex_match(rawInfo->name, results, lightPattern)) {
- std::string commonName = results[1].str();
- int32_t playerId = std::stoi(results[2]);
- if (playerIdLightIds.empty()) {
- playerIdName = commonName;
- playerIdLightIds.insert_or_assign(playerId, rawId);
- } else {
- // Make sure the player ID leds have common string name
- if (playerIdName.compare(commonName) == 0 &&
- playerIdLightIds.find(playerId) == playerIdLightIds.end()) {
- playerIdLightIds.insert_or_assign(playerId, rawId);
- }
- }
- }
- // Check if this is an LED of RGB light
- if (rawInfo->flags.test(InputLightClass::RED)) {
- hasRedLed = true;
- rawRgbIds.emplace(LightColor::RED, rawId);
- }
- if (rawInfo->flags.test(InputLightClass::GREEN)) {
- hasGreenLed = true;
- rawRgbIds.emplace(LightColor::GREEN, rawId);
- }
- if (rawInfo->flags.test(InputLightClass::BLUE)) {
- hasBlueLed = true;
- rawRgbIds.emplace(LightColor::BLUE, rawId);
- }
- if (rawInfo->flags.test(InputLightClass::GLOBAL)) {
- rawGlobalId = rawId;
- }
- if (DEBUG_LIGHT_DETAILS) {
- ALOGD("Light rawId %d name %s max %d flags %s \n", rawInfo->id,
- rawInfo->name.c_str(), rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS),
- rawInfo->flags.string().c_str());
- }
- }
-
- // Construct a player ID light
- if (playerIdLightIds.size() > 1) {
- std::unique_ptr<Light> light =
- std::make_unique<PlayerIdLight>(getDeviceContext(), playerIdName, ++mNextId,
- playerIdLightIds);
- mLights.insert_or_assign(light->id, std::move(light));
- // Remove these raw lights from raw light info as they've been used to compose a
- // Player ID light, so we do not expose these raw lights as single lights.
- for (const auto& [playerId, rawId] : playerIdLightIds) {
- rawInfos.erase(rawId);
- }
- }
- // Construct a RGB light for composed RGB light
- if (hasRedLed && hasGreenLed && hasBlueLed) {
- if (DEBUG_LIGHT_DETAILS) {
- ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED),
- rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
- }
- std::unique_ptr<Light> light = std::make_unique<RgbLight>(getDeviceContext(), ++mNextId,
- 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));
- rawInfos.erase(rawRgbIds.at(LightColor::GREEN));
- rawInfos.erase(rawRgbIds.at(LightColor::BLUE));
- if (rawGlobalId.has_value()) {
- rawInfos.erase(rawGlobalId.value());
- }
- }
-
- // Check the rest of raw light infos
- for (const auto& [rawId, rawInfo] : rawInfos) {
- // 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)) {
- if (DEBUG_LIGHT_DETAILS) {
- ALOGD("Multicolor light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
- }
- std::unique_ptr<Light> light =
- std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name,
- ++mNextId, rawInfo.id);
- mLights.insert_or_assign(light->id, std::move(light));
- continue;
- }
- // Construct a single LED light
- if (DEBUG_LIGHT_DETAILS) {
- ALOGD("Single light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
- }
- std::unique_ptr<Light> light =
- std::make_unique<SingleLight>(getDeviceContext(), rawInfo.name, ++mNextId,
- rawInfo.id);
-
- mLights.insert_or_assign(light->id, std::move(light));
- }
- }
-}
-
-void LightInputMapper::reset(nsecs_t when) {
- InputMapper::reset(when);
-}
-
-void LightInputMapper::process(const RawEvent* rawEvent) {}
-
-bool LightInputMapper::setLightColor(int32_t lightId, int32_t color) {
- auto it = mLights.find(lightId);
- if (it == mLights.end()) {
- return false;
- }
- auto& light = it->second;
- if (DEBUG_LIGHT_DETAILS) {
- ALOGD("setLightColor lightId %d type %s color 0x%x", lightId,
- NamedEnum::string(light->type).c_str(), color);
- }
- return light->setLightColor(color);
-}
-
-std::optional<int32_t> LightInputMapper::getLightColor(int32_t lightId) {
- auto it = mLights.find(lightId);
- if (it == mLights.end()) {
- return std::nullopt;
- }
- auto& light = it->second;
- std::optional<int32_t> color = light->getLightColor();
- if (DEBUG_LIGHT_DETAILS) {
- ALOGD("getLightColor lightId %d type %s color 0x%x", lightId,
- NamedEnum::string(light->type).c_str(), color.value_or(0));
- }
- return color;
-}
-
-bool LightInputMapper::setLightPlayerId(int32_t lightId, int32_t playerId) {
- auto it = mLights.find(lightId);
- if (it == mLights.end()) {
- return false;
- }
- auto& light = it->second;
- return light->setLightPlayerId(playerId);
-}
-
-std::optional<int32_t> LightInputMapper::getLightPlayerId(int32_t lightId) {
- auto it = mLights.find(lightId);
- if (it == mLights.end()) {
- return std::nullopt;
- }
- auto& light = it->second;
- return light->getLightPlayerId();
-}
-
-} // namespace android
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index d69bb6a..3d99a6b 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-#include <BatteryInputMapper.h>
#include <CursorInputMapper.h>
+#include <InputController.h>
#include <InputDevice.h>
#include <InputMapper.h>
#include <InputReader.h>
#include <InputReaderBase.h>
#include <InputReaderFactory.h>
#include <KeyboardInputMapper.h>
-#include <LightInputMapper.h>
#include <MultiTouchInputMapper.h>
#include <SensorInputMapper.h>
#include <SingleTouchInputMapper.h>
@@ -71,6 +70,7 @@
static constexpr int32_t FIRST_TRACKING_ID = 0;
static constexpr int32_t SECOND_TRACKING_ID = 1;
static constexpr int32_t THIRD_TRACKING_ID = 2;
+static constexpr int32_t DEFAULT_BATTERY = 1;
static constexpr int32_t BATTERY_STATUS = 4;
static constexpr int32_t BATTERY_CAPACITY = 66;
static constexpr int32_t LIGHT_BRIGHTNESS = 0x55000000;
@@ -895,9 +895,19 @@
std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; };
- std::optional<int32_t> getBatteryCapacity(int32_t) const override { return BATTERY_CAPACITY; }
+ std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override {
+ return BATTERY_CAPACITY;
+ }
- std::optional<int32_t> getBatteryStatus(int32_t) const override { return BATTERY_STATUS; }
+ std::optional<int32_t> getBatteryStatus(int32_t, int32_t) const override {
+ return BATTERY_STATUS;
+ }
+
+ const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) { return {}; }
+
+ std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, int32_t batteryId) {
+ return std::nullopt;
+ }
const std::vector<int32_t> getRawLightIds(int32_t deviceId) override {
std::vector<int32_t> ids;
@@ -2005,56 +2015,25 @@
ASSERT_EQ(mReader->getVibratorIds(deviceId).size(), 2U);
}
-class FakeBatteryInputMapper : public FakeInputMapper {
-public:
- FakeBatteryInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
- : FakeInputMapper(deviceContext, sources) {}
+// --- FakeInputController ---
- std::optional<int32_t> getBatteryCapacity() override {
- return getDeviceContext().getBatteryCapacity();
+class FakeInputController : public InputControllerInterface {
+public:
+ FakeInputController(InputDeviceContext& deviceContext) : mDeviceContext(deviceContext) {}
+
+ ~FakeInputController() override {}
+
+ void populateDeviceInfo(InputDeviceInfo* deviceInfo) override {}
+
+ void dump(std::string& dump) override {}
+
+ std::optional<int32_t> getBatteryCapacity(int32_t batteryId) override {
+ return getDeviceContext().getBatteryCapacity(batteryId);
}
- std::optional<int32_t> getBatteryStatus() override {
- return getDeviceContext().getBatteryStatus();
+ std::optional<int32_t> getBatteryStatus(int32_t batteryId) override {
+ return getDeviceContext().getBatteryStatus(batteryId);
}
-};
-
-TEST_F(InputReaderTest, BatteryGetCapacity) {
- constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
- constexpr int32_t eventHubId = 1;
- const char* DEVICE_LOCATION = "BLUETOOTH";
- std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
- FakeBatteryInputMapper& mapper =
- device->addMapper<FakeBatteryInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
- mReader->pushNextDevice(device);
-
- ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
- ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
-
- ASSERT_EQ(mReader->getBatteryCapacity(deviceId), BATTERY_CAPACITY);
-}
-
-TEST_F(InputReaderTest, BatteryGetStatus) {
- constexpr int32_t deviceId = END_RESERVED_ID + 1000;
- Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
- constexpr int32_t eventHubId = 1;
- const char* DEVICE_LOCATION = "BLUETOOTH";
- std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
- FakeBatteryInputMapper& mapper =
- device->addMapper<FakeBatteryInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
- mReader->pushNextDevice(device);
-
- ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
- ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
-
- ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS);
-}
-
-class FakeLightInputMapper : public FakeInputMapper {
-public:
- FakeLightInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
- : FakeInputMapper(deviceContext, sources) {}
bool setLightColor(int32_t lightId, int32_t color) override {
getDeviceContext().setLightBrightness(lightId, color >> 24);
@@ -2068,16 +2047,54 @@
}
return result.value() << 24;
}
+
+ bool setLightPlayerId(int32_t lightId, int32_t playerId) override { return true; }
+
+ std::optional<int32_t> getLightPlayerId(int32_t lightId) override { return std::nullopt; }
+
+private:
+ InputDeviceContext& mDeviceContext;
+ inline int32_t getDeviceId() { return mDeviceContext.getId(); }
+ inline InputDeviceContext& getDeviceContext() { return mDeviceContext; }
};
+TEST_F(InputReaderTest, BatteryGetCapacity) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+ constexpr int32_t eventHubId = 1;
+ const char* DEVICE_LOCATION = "BLUETOOTH";
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+ FakeInputController& controller = device->addController<FakeInputController>(eventHubId);
+ mReader->pushNextDevice(device);
+
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+
+ ASSERT_EQ(controller.getBatteryCapacity(DEFAULT_BATTERY), BATTERY_CAPACITY);
+ ASSERT_EQ(mReader->getBatteryCapacity(deviceId), BATTERY_CAPACITY);
+}
+
+TEST_F(InputReaderTest, BatteryGetStatus) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+ constexpr int32_t eventHubId = 1;
+ const char* DEVICE_LOCATION = "BLUETOOTH";
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+ FakeInputController& controller = device->addController<FakeInputController>(eventHubId);
+ mReader->pushNextDevice(device);
+
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+
+ ASSERT_EQ(controller.getBatteryStatus(DEFAULT_BATTERY), BATTERY_STATUS);
+ ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS);
+}
+
TEST_F(InputReaderTest, LightGetColor) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT;
constexpr int32_t eventHubId = 1;
const char* DEVICE_LOCATION = "BLUETOOTH";
std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
- FakeLightInputMapper& mapper =
- device->addMapper<FakeLightInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
+ FakeInputController& controller = device->addController<FakeInputController>(eventHubId);
mReader->pushNextDevice(device);
RawLightInfo info = {.id = 1,
.name = "Mono",
@@ -2088,8 +2105,9 @@
mFakeEventHub->fakeLightBrightness(1 /* rawId */, 0x55);
ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
- ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
+ ASSERT_TRUE(controller.setLightColor(1 /* lightId */, LIGHT_BRIGHTNESS));
+ ASSERT_EQ(controller.getLightColor(1 /* lightId */), LIGHT_BRIGHTNESS);
ASSERT_TRUE(mReader->setLightColor(deviceId, 1 /* lightId */, LIGHT_BRIGHTNESS));
ASSERT_EQ(mReader->getLightColor(deviceId, 1 /* lightId */), LIGHT_BRIGHTNESS);
}
@@ -2989,154 +3007,6 @@
mapper.flushSensor(InputDeviceSensorType::GYROSCOPE);
}
-// --- BatteryInputMapperTest ---
-class BatteryInputMapperTest : public InputMapperTest {
-protected:
- void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::BATTERY); }
-};
-
-TEST_F(BatteryInputMapperTest, GetSources) {
- BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>();
-
- ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources());
-}
-
-TEST_F(BatteryInputMapperTest, GetBatteryCapacity) {
- BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>();
-
- ASSERT_TRUE(mapper.getBatteryCapacity());
- ASSERT_EQ(mapper.getBatteryCapacity().value_or(-1), BATTERY_CAPACITY);
-}
-
-TEST_F(BatteryInputMapperTest, GetBatteryStatus) {
- BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>();
-
- ASSERT_TRUE(mapper.getBatteryStatus());
- ASSERT_EQ(mapper.getBatteryStatus().value_or(-1), BATTERY_STATUS);
-}
-
-// --- LightInputMapperTest ---
-class LightInputMapperTest : public InputMapperTest {
-protected:
- void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::LIGHT); }
-};
-
-TEST_F(LightInputMapperTest, GetSources) {
- LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
-
- ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources());
-}
-
-TEST_F(LightInputMapperTest, SingleLight) {
- RawLightInfo infoSingle = {.id = 1,
- .name = "Mono",
- .maxBrightness = 255,
- .flags = InputLightClass::BRIGHTNESS,
- .path = ""};
- mFakeEventHub->addRawLightInfo(infoSingle.id, std::move(infoSingle));
-
- LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
- InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
- const auto& ids = info.getLightIds();
- ASSERT_EQ(1UL, ids.size());
- ASSERT_EQ(InputDeviceLightType::SINGLE, info.getLightInfo(ids[0])->type);
-
- ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_BRIGHTNESS));
- ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_BRIGHTNESS);
-}
-
-TEST_F(LightInputMapperTest, RGBLight) {
- 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 = ""};
- mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed));
- mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen));
- mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue));
-
- LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
- InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
- const auto& ids = info.getLightIds();
- ASSERT_EQ(1UL, ids.size());
- ASSERT_EQ(InputDeviceLightType::RGB, info.getLightInfo(ids[0])->type);
-
- ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_COLOR));
- ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR);
-}
-
-TEST_F(LightInputMapperTest, MultiColorRGBLight) {
- RawLightInfo infoColor = {.id = 1,
- .name = "red",
- .maxBrightness = 255,
- .flags = InputLightClass::BRIGHTNESS |
- InputLightClass::MULTI_INTENSITY |
- InputLightClass::MULTI_INDEX,
- .path = ""};
-
- mFakeEventHub->addRawLightInfo(infoColor.id, std::move(infoColor));
-
- LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
- InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
- const auto& ids = info.getLightIds();
- ASSERT_EQ(1UL, ids.size());
- ASSERT_EQ(InputDeviceLightType::MULTI_COLOR, info.getLightInfo(ids[0])->type);
-
- ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_COLOR));
- ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR);
-}
-
-TEST_F(LightInputMapperTest, PlayerIdLight) {
- RawLightInfo info1 = {.id = 1,
- .name = "player1",
- .maxBrightness = 255,
- .flags = InputLightClass::BRIGHTNESS,
- .path = ""};
- RawLightInfo info2 = {.id = 2,
- .name = "player2",
- .maxBrightness = 255,
- .flags = InputLightClass::BRIGHTNESS,
- .path = ""};
- RawLightInfo info3 = {.id = 3,
- .name = "player3",
- .maxBrightness = 255,
- .flags = InputLightClass::BRIGHTNESS,
- .path = ""};
- RawLightInfo info4 = {.id = 4,
- .name = "player4",
- .maxBrightness = 255,
- .flags = InputLightClass::BRIGHTNESS,
- .path = ""};
- mFakeEventHub->addRawLightInfo(info1.id, std::move(info1));
- mFakeEventHub->addRawLightInfo(info2.id, std::move(info2));
- mFakeEventHub->addRawLightInfo(info3.id, std::move(info3));
- mFakeEventHub->addRawLightInfo(info4.id, std::move(info4));
-
- LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>();
- InputDeviceInfo info;
- mapper.populateDeviceInfo(&info);
- const auto& ids = info.getLightIds();
- ASSERT_EQ(1UL, ids.size());
- ASSERT_EQ(InputDeviceLightType::PLAYER_ID, info.getLightInfo(ids[0])->type);
-
- ASSERT_FALSE(mapper.setLightColor(ids[0], LIGHT_COLOR));
- ASSERT_TRUE(mapper.setLightPlayerId(ids[0], LIGHT_PLAYER_ID));
- ASSERT_EQ(mapper.getLightPlayerId(ids[0]).value_or(-1), LIGHT_PLAYER_ID);
-}
-
// --- KeyboardInputMapperTest ---
class KeyboardInputMapperTest : public InputMapperTest {
@@ -8728,4 +8598,216 @@
ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
}
+// --- InputControllerTest ---
+
+class InputControllerTest : public testing::Test {
+protected:
+ static const char* DEVICE_NAME;
+ static const char* DEVICE_LOCATION;
+ static const int32_t DEVICE_ID;
+ static const int32_t DEVICE_GENERATION;
+ static const int32_t DEVICE_CONTROLLER_NUMBER;
+ static const Flags<InputDeviceClass> DEVICE_CLASSES;
+ static const int32_t EVENTHUB_ID;
+
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
+ sp<FakeInputReaderPolicy> mFakePolicy;
+ sp<TestInputListener> mFakeListener;
+ std::unique_ptr<InstrumentedInputReader> mReader;
+ std::shared_ptr<InputDevice> mDevice;
+
+ virtual void SetUp(Flags<InputDeviceClass> classes) {
+ mFakeEventHub = std::make_unique<FakeEventHub>();
+ mFakePolicy = new FakeInputReaderPolicy();
+ mFakeListener = new TestInputListener();
+ mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
+ mFakeListener);
+ mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
+ }
+
+ void SetUp() override { SetUp(DEVICE_CLASSES); }
+
+ void TearDown() override {
+ mFakeListener.clear();
+ mFakePolicy.clear();
+ }
+
+ void configureDevice(uint32_t changes) {
+ if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ mReader->requestRefreshConfiguration(changes);
+ mReader->loopOnce();
+ }
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+ }
+
+ std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
+ const std::string& location, int32_t eventHubId,
+ Flags<InputDeviceClass> classes) {
+ InputDeviceIdentifier identifier;
+ identifier.name = name;
+ identifier.location = location;
+ std::shared_ptr<InputDevice> device =
+ std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION,
+ identifier);
+ mReader->pushNextDevice(device);
+ mFakeEventHub->addDevice(eventHubId, name, classes);
+ mReader->loopOnce();
+ return device;
+ }
+
+ template <class T, typename... Args>
+ T& addControllerAndConfigure(Args... args) {
+ T& controller = mDevice->addController<T>(EVENTHUB_ID, args...);
+
+ return controller;
+ }
+};
+
+const char* InputControllerTest::DEVICE_NAME = "device";
+const char* InputControllerTest::DEVICE_LOCATION = "BLUETOOTH";
+const int32_t InputControllerTest::DEVICE_ID = END_RESERVED_ID + 1000;
+const int32_t InputControllerTest::DEVICE_GENERATION = 2;
+const int32_t InputControllerTest::DEVICE_CONTROLLER_NUMBER = 0;
+const Flags<InputDeviceClass> InputControllerTest::DEVICE_CLASSES =
+ Flags<InputDeviceClass>(0); // not needed for current tests
+const int32_t InputControllerTest::EVENTHUB_ID = 1;
+
+// --- BatteryControllerTest ---
+class BatteryControllerTest : public InputControllerTest {
+protected:
+ void SetUp() override {
+ InputControllerTest::SetUp(DEVICE_CLASSES | InputDeviceClass::BATTERY);
+ }
+};
+
+TEST_F(BatteryControllerTest, GetBatteryCapacity) {
+ InputController& controller = addControllerAndConfigure<InputController>();
+
+ ASSERT_TRUE(controller.getBatteryCapacity(DEFAULT_BATTERY));
+ ASSERT_EQ(controller.getBatteryCapacity(DEFAULT_BATTERY).value_or(-1), BATTERY_CAPACITY);
+}
+
+TEST_F(BatteryControllerTest, GetBatteryStatus) {
+ InputController& controller = addControllerAndConfigure<InputController>();
+
+ ASSERT_TRUE(controller.getBatteryStatus(DEFAULT_BATTERY));
+ ASSERT_EQ(controller.getBatteryStatus(DEFAULT_BATTERY).value_or(-1), BATTERY_STATUS);
+}
+
+// --- LightControllerTest ---
+class LightControllerTest : public InputControllerTest {
+protected:
+ void SetUp() override { InputControllerTest::SetUp(DEVICE_CLASSES | InputDeviceClass::LIGHT); }
+};
+
+TEST_F(LightControllerTest, SingleLight) {
+ RawLightInfo infoSingle = {.id = 1,
+ .name = "Mono",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(infoSingle.id, std::move(infoSingle));
+
+ InputController& controller = addControllerAndConfigure<InputController>();
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ const auto& ids = info.getLightIds();
+ ASSERT_EQ(1UL, ids.size());
+ ASSERT_EQ(InputDeviceLightType::SINGLE, info.getLightInfo(ids[0])->type);
+
+ ASSERT_TRUE(controller.setLightColor(ids[0], LIGHT_BRIGHTNESS));
+ ASSERT_EQ(controller.getLightColor(ids[0]).value_or(-1), LIGHT_BRIGHTNESS);
+}
+
+TEST_F(LightControllerTest, RGBLight) {
+ 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 = ""};
+ mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed));
+ mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen));
+ mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue));
+
+ InputController& controller = addControllerAndConfigure<InputController>();
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ const auto& ids = info.getLightIds();
+ ASSERT_EQ(1UL, ids.size());
+ ASSERT_EQ(InputDeviceLightType::RGB, info.getLightInfo(ids[0])->type);
+
+ ASSERT_TRUE(controller.setLightColor(ids[0], LIGHT_COLOR));
+ ASSERT_EQ(controller.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR);
+}
+
+TEST_F(LightControllerTest, MultiColorRGBLight) {
+ RawLightInfo infoColor = {.id = 1,
+ .name = "red",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS |
+ InputLightClass::MULTI_INTENSITY |
+ InputLightClass::MULTI_INDEX,
+ .path = ""};
+
+ mFakeEventHub->addRawLightInfo(infoColor.id, std::move(infoColor));
+
+ InputController& controller = addControllerAndConfigure<InputController>();
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ const auto& ids = info.getLightIds();
+ ASSERT_EQ(1UL, ids.size());
+ ASSERT_EQ(InputDeviceLightType::MULTI_COLOR, info.getLightInfo(ids[0])->type);
+
+ ASSERT_TRUE(controller.setLightColor(ids[0], LIGHT_COLOR));
+ ASSERT_EQ(controller.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR);
+}
+
+TEST_F(LightControllerTest, PlayerIdLight) {
+ RawLightInfo info1 = {.id = 1,
+ .name = "player1",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ RawLightInfo info2 = {.id = 2,
+ .name = "player2",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ RawLightInfo info3 = {.id = 3,
+ .name = "player3",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ RawLightInfo info4 = {.id = 4,
+ .name = "player4",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(info1.id, std::move(info1));
+ mFakeEventHub->addRawLightInfo(info2.id, std::move(info2));
+ mFakeEventHub->addRawLightInfo(info3.id, std::move(info3));
+ mFakeEventHub->addRawLightInfo(info4.id, std::move(info4));
+
+ InputController& controller = addControllerAndConfigure<InputController>();
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ const auto& ids = info.getLightIds();
+ ASSERT_EQ(1UL, ids.size());
+ ASSERT_EQ(InputDeviceLightType::PLAYER_ID, info.getLightInfo(ids[0])->type);
+
+ ASSERT_FALSE(controller.setLightColor(ids[0], LIGHT_COLOR));
+ ASSERT_TRUE(controller.setLightPlayerId(ids[0], LIGHT_PLAYER_ID));
+ ASSERT_EQ(controller.getLightPlayerId(ids[0]).value_or(-1), LIGHT_PLAYER_ID);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 470059a..b976eb5 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -157,6 +157,7 @@
"FpsReporter.cpp",
"FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
+ "HdrLayerInfoReporter.cpp",
"Layer.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 8402149..a45be8a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -55,6 +55,16 @@
std::vector<uint8_t> value;
std::string dumpAsString() const;
+
+ struct Hasher {
+ size_t operator()(const GenericLayerMetadataEntry& entry) const {
+ size_t hash = 0;
+ for (const auto value : entry.value) {
+ hashCombineSingleHashed(hash, value);
+ }
+ return hash;
+ }
+ };
};
inline bool operator==(const GenericLayerMetadataEntry& lhs, const GenericLayerMetadataEntry& rhs) {
@@ -70,6 +80,8 @@
/*
* Used by LayerFE::getCompositionState
+ * Note that fields that affect HW composer state may need to be mirrored into
+ * android::compositionengine::impl::planner::LayerState
*/
struct LayerFECompositionState {
// If set to true, forces client composition on all output layers until
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 6c02759..ca70750 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -48,6 +48,8 @@
namespace compositionengine::impl {
+// Note that fields that affect HW composer state may need to be mirrored into
+// android::compositionengine::impl::planner::LayerState
struct OutputLayerCompositionState {
// The portion of the layer that is not obscured by opaque layers on top
Region visibleRegion;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index d005ca3..e422f57 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -57,13 +57,16 @@
BufferTransform = 1u << 5,
BlendMode = 1u << 6,
Alpha = 1u << 7,
- VisibleRegion = 1u << 8,
- Dataspace = 1u << 9,
- ColorTransform = 1u << 10,
- CompositionType = 1u << 11,
- SidebandStream = 1u << 12,
- Buffer = 1u << 13,
- SolidColor = 1u << 14,
+ LayerMetadata = 1u << 8,
+ VisibleRegion = 1u << 9,
+ Dataspace = 1u << 10,
+ PixelFormat = 1u << 11,
+ ColorTransform = 1u << 12,
+ SurfaceDamage = 1u << 13,
+ CompositionType = 1u << 14,
+ SidebandStream = 1u << 15,
+ Buffer = 1u << 16,
+ SolidColor = 1u << 17,
};
// clang-format on
@@ -95,6 +98,7 @@
using ReadFromLayerState = std::function<T(const compositionengine::OutputLayer* layer)>;
using ToStrings = std::function<std::vector<std::string>(const T&)>;
using Equals = std::function<bool(const T&, const T&)>;
+ using Hashes = std::function<size_t(const T&)>;
static ToStrings getDefaultToStrings() {
return [](const T& value) {
@@ -107,14 +111,38 @@
return [](const T& value) { return std::vector<std::string>{toString(value)}; };
}
+ static ToStrings getRegionToStrings() {
+ return [](const Region& region) {
+ using namespace std::string_literals;
+ std::string dump;
+ region.dump(dump, "");
+ std::vector<std::string> split = base::Split(dump, "\n"s);
+ split.erase(split.begin()); // Strip the header
+ split.pop_back(); // Strip the last (empty) line
+ for (std::string& line : split) {
+ line.erase(0, 4); // Strip leading padding before each rect
+ }
+ return split;
+ };
+ }
+
static Equals getDefaultEquals() {
return [](const T& lhs, const T& rhs) { return lhs == rhs; };
}
+ static Equals getRegionEquals() {
+ return [](const Region& lhs, const Region& rhs) { return lhs.hasSameRects(rhs); };
+ }
+
+ static Hashes getDefaultHashes() {
+ return [](const T& value) { return std::hash<T>{}(value); };
+ }
+
OutputLayerState(ReadFromLayerState reader,
ToStrings toStrings = OutputLayerState::getDefaultToStrings(),
- Equals equals = OutputLayerState::getDefaultEquals())
- : mReader(reader), mToStrings(toStrings), mEquals(equals) {}
+ Equals equals = OutputLayerState::getDefaultEquals(),
+ Hashes hashes = OutputLayerState::getDefaultHashes())
+ : mReader(reader), mToStrings(toStrings), mEquals(equals), mHashes(hashes) {}
~OutputLayerState() override = default;
@@ -138,7 +166,7 @@
size_t getHash() const override {
if (!mHash) {
- mHash = std::hash<T>{}(mValue);
+ mHash = mHashes(mValue);
}
return *mHash;
}
@@ -172,6 +200,7 @@
const ReadFromLayerState mReader;
const ToStrings mToStrings;
const Equals mEquals;
+ const Hashes mHashes;
T mValue = {};
mutable std::optional<size_t> mHash = {};
};
@@ -263,39 +292,80 @@
OutputLayerState<float, LayerStateField::Alpha> mAlpha{
[](auto layer) { return layer->getLayerFE().getCompositionState()->alpha; }};
- // TODO(b/180638831): Generic layer metadata
+ using LayerMetadataState =
+ OutputLayerState<GenericLayerMetadataMap, LayerStateField::LayerMetadata>;
+ LayerMetadataState
+ mLayerMetadata{[](auto layer) {
+ return layer->getLayerFE().getCompositionState()->metadata;
+ },
+ [](const GenericLayerMetadataMap& metadata) {
+ std::vector<std::string> result;
+ if (metadata.empty()) {
+ result.push_back("{}");
+ return result;
+ }
+ result.push_back("{");
+ for (const auto& [key, value] : metadata) {
+ std::string keyValueDump;
+ keyValueDump.append(" ");
+ keyValueDump.append(key);
+ keyValueDump.append("=");
+ keyValueDump.append(value.dumpAsString());
+ result.push_back(keyValueDump);
+ }
+ result.push_back("}");
+ return result;
+ },
+ LayerMetadataState::getDefaultEquals(),
+ [](const GenericLayerMetadataMap& metadata) {
+ size_t hash = 0;
+ for (const auto& [key, value] : metadata) {
+ size_t entryHash = 0;
+ hashCombineSingleHashed(entryHash,
+ std::hash<std::string>{}(key));
+ hashCombineSingleHashed(entryHash,
+ GenericLayerMetadataEntry::Hasher{}(
+ value));
+ hash ^= entryHash;
+ }
+ return hash;
+ }};
// Output-dependent per-frame state
- OutputLayerState<Region, LayerStateField::VisibleRegion>
- mVisibleRegion{[](auto layer) { return layer->getState().visibleRegion; },
- [](const Region& region) {
- using namespace std::string_literals;
- std::string dump;
- region.dump(dump, "");
- std::vector<std::string> split = base::Split(dump, "\n"s);
- split.erase(split.begin()); // Strip the header
- split.pop_back(); // Strip the last (empty) line
- for (std::string& line : split) {
- line.erase(0, 4); // Strip leading padding before each rect
- }
- return split;
- },
- [](const Region& lhs, const Region& rhs) {
- return lhs.hasSameRects(rhs);
- }};
+ using VisibleRegionState = OutputLayerState<Region, LayerStateField::VisibleRegion>;
+ VisibleRegionState mVisibleRegion{[](auto layer) { return layer->getState().visibleRegion; },
+ VisibleRegionState::getRegionToStrings(),
+ VisibleRegionState::getRegionEquals()};
using DataspaceState = OutputLayerState<ui::Dataspace, LayerStateField::Dataspace>;
DataspaceState mOutputDataspace{[](auto layer) { return layer->getState().dataspace; },
DataspaceState::getHalToStrings()};
- // TODO(b/180638831): Buffer format
-
// Output-independent per-frame state
+ using PixelFormatState = OutputLayerState<hardware::graphics::composer::hal::PixelFormat,
+ LayerStateField::PixelFormat>;
+ PixelFormatState
+ mPixelFormat{[](auto layer) {
+ return layer->getLayerFE().getCompositionState()->buffer
+ ? static_cast<hardware::graphics::composer::hal::PixelFormat>(
+ layer->getLayerFE()
+ .getCompositionState()
+ ->buffer->getPixelFormat())
+ : hardware::graphics::composer::hal::PixelFormat::RGBA_8888;
+ },
+ PixelFormatState::getHalToStrings()};
+
OutputLayerState<mat4, LayerStateField::ColorTransform> mColorTransform;
- // TODO(b/180638831): Surface damage
+ using SurfaceDamageState = OutputLayerState<Region, LayerStateField::SurfaceDamage>;
+ SurfaceDamageState
+ mSurfaceDamage{[](auto layer) {
+ return layer->getLayerFE().getCompositionState()->surfaceDamage;
+ },
+ SurfaceDamageState::getRegionToStrings(),
+ SurfaceDamageState::getRegionEquals()};
using CompositionTypeState = OutputLayerState<hardware::graphics::composer::hal::Composition,
LayerStateField::CompositionType>;
@@ -339,10 +409,12 @@
return std::vector<std::string>{stream.str()};
}};
- std::array<StateInterface*, 13> getNonUniqueFields() {
- std::array<const StateInterface*, 13> constFields =
+ static const constexpr size_t kNumNonUniqueFields = 16;
+
+ std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() {
+ std::array<const StateInterface*, kNumNonUniqueFields> constFields =
const_cast<const LayerState*>(this)->getNonUniqueFields();
- std::array<StateInterface*, 13> fields;
+ std::array<StateInterface*, kNumNonUniqueFields> fields;
std::transform(constFields.cbegin(), constFields.cend(), fields.begin(),
[](const StateInterface* constField) {
return const_cast<StateInterface*>(constField);
@@ -350,12 +422,12 @@
return fields;
}
- std::array<const StateInterface*, 13> getNonUniqueFields() const {
+ std::array<const StateInterface*, kNumNonUniqueFields> getNonUniqueFields() const {
return {
- &mDisplayFrame, &mSourceCrop, &mZOrder, &mBufferTransform,
- &mBlendMode, &mAlpha, &mVisibleRegion, &mOutputDataspace,
- &mColorTransform, &mCompositionType, &mSidebandStream, &mBuffer,
- &mSolidColor,
+ &mDisplayFrame, &mSourceCrop, &mZOrder, &mBufferTransform,
+ &mBlendMode, &mAlpha, &mLayerMetadata, &mVisibleRegion,
+ &mOutputDataspace, &mPixelFormat, &mColorTransform, &mSurfaceDamage,
+ &mCompositionType, &mSidebandStream, &mBuffer, &mSolidColor,
};
}
};
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index f58addb..5516905 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -178,6 +178,7 @@
};
std::vector<renderengine::LayerSettings> layerSettings;
+ renderengine::LayerSettings highlight;
for (const auto& layer : mLayers) {
const auto clientCompositionList =
layer.getState()->getOutputLayer()->getLayerFE().prepareClientCompositionList(
@@ -192,7 +193,7 @@
[](const renderengine::LayerSettings& settings) { return &settings; });
if (sDebugHighlighLayers) {
- renderengine::LayerSettings highlight{
+ highlight = {
.geometry =
renderengine::Geometry{
.boundaries = FloatRect(0.0f, 0.0f,
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index e976c9b..7c32e94 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -157,9 +157,11 @@
return lhs.mId == rhs.mId && lhs.mName == rhs.mName && lhs.mDisplayFrame == rhs.mDisplayFrame &&
lhs.mSourceCrop == rhs.mSourceCrop && lhs.mZOrder == rhs.mZOrder &&
lhs.mBufferTransform == rhs.mBufferTransform && lhs.mBlendMode == rhs.mBlendMode &&
- lhs.mAlpha == rhs.mAlpha && lhs.mVisibleRegion == rhs.mVisibleRegion &&
- lhs.mOutputDataspace == rhs.mOutputDataspace &&
+ lhs.mAlpha == rhs.mAlpha && lhs.mLayerMetadata == rhs.mLayerMetadata &&
+ lhs.mVisibleRegion == rhs.mVisibleRegion &&
+ lhs.mOutputDataspace == rhs.mOutputDataspace && lhs.mPixelFormat == rhs.mPixelFormat &&
lhs.mColorTransform == rhs.mColorTransform &&
+ lhs.mSurfaceDamage == rhs.mSurfaceDamage &&
lhs.mCompositionType == rhs.mCompositionType &&
lhs.mSidebandStream == rhs.mSidebandStream && lhs.mBuffer == rhs.mBuffer &&
(lhs.mCompositionType.get() != hal::Composition::SOLID_COLOR ||
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index d5a7234..c1b25e6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -24,6 +24,9 @@
#include <gtest/gtest.h>
#include <log/log.h>
+#include "android/hardware_buffer.h"
+#include "compositionengine/LayerFECompositionState.h"
+
namespace android::compositionengine::impl::planner {
namespace {
@@ -48,7 +51,15 @@
native_handle_t* const sFakeSidebandStreamOne = reinterpret_cast<native_handle_t*>(10);
native_handle_t* const sFakeSidebandStreamTwo = reinterpret_cast<native_handle_t*>(11);
const half4 sHalf4One = half4(0.2f, 0.3f, 0.4f, 0.5f);
-const half4 sHalf4Two = half4(0.5f, 0.4f, 0.43, 0.2f);
+const half4 sHalf4Two = half4(0.5f, 0.4f, 0.3f, 0.2f);
+const std::string sMetadataKeyOne = std::string("Meta!");
+const std::string sMetadataKeyTwo = std::string("Data!");
+const GenericLayerMetadataEntry sMetadataValueOne = GenericLayerMetadataEntry{
+ .value = std::vector<uint8_t>({1, 2}),
+};
+const GenericLayerMetadataEntry sMetadataValueTwo = GenericLayerMetadataEntry{
+ .value = std::vector<uint8_t>({1, 3}),
+};
struct LayerStateTest : public testing::Test {
LayerStateTest() {
@@ -75,6 +86,21 @@
EXPECT_CALL(layerFE, getCompositionState()).WillRepeatedly(Return(&layerFEState));
}
+ void verifyUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs) {
+ EXPECT_EQ(lhs.getHash(), rhs.getHash());
+
+ EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), lhs.getDifferingFields(rhs));
+ EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), rhs.getDifferingFields(lhs));
+ }
+
+ void verifyNonUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs,
+ Flags<LayerStateField> fields) {
+ EXPECT_NE(lhs.getHash(), rhs.getHash());
+
+ EXPECT_EQ(fields, lhs.getDifferingFields(rhs));
+ EXPECT_EQ(fields, rhs.getDifferingFields(lhs));
+ }
+
mock::LayerFE mLayerFE;
mock::OutputLayer mOutputLayer;
std::unique_ptr<LayerState> mLayerState;
@@ -129,14 +155,7 @@
EXPECT_NE(mLayerState->getId(), otherLayerState->getId());
// Id is a unique field, so it's not computed in the hash for a layer state.
- EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash());
-
- // Similarly, Id cannot be included in differing fields.
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
- otherLayerState->getDifferingFields(*mLayerState));
-
+ verifyUniqueDifferingFields(*mLayerState, *otherLayerState);
EXPECT_FALSE(mLayerState->compare(*otherLayerState));
EXPECT_FALSE(otherLayerState->compare(*mLayerState));
}
@@ -181,14 +200,7 @@
EXPECT_NE(mLayerState->getName(), otherLayerState->getName());
// Name is a unique field, so it's not computed in the hash for a layer state.
- EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash());
-
- // Similarly, Name cannot be included in differing fields.
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
- otherLayerState->getDifferingFields(*mLayerState));
-
+ verifyUniqueDifferingFields(*mLayerState, *otherLayerState);
EXPECT_FALSE(mLayerState->compare(*otherLayerState));
EXPECT_FALSE(otherLayerState->compare(*mLayerState));
}
@@ -239,13 +251,7 @@
EXPECT_NE(mLayerState->getDisplayFrame(), otherLayerState->getDisplayFrame());
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::DisplayFrame),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::DisplayFrame),
- otherLayerState->getDifferingFields(*mLayerState));
-
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::DisplayFrame);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
}
@@ -316,13 +322,8 @@
EXPECT_NE(mLayerState->getCompositionType(), otherLayerState->getCompositionType());
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::CompositionType),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::CompositionType),
- otherLayerState->getDifferingFields(*mLayerState));
-
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState,
+ LayerStateField::CompositionType);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
}
@@ -360,12 +361,8 @@
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- // Buffers are not included in differing fields or in hashes.
- EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash());
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
- otherLayerState->getDifferingFields(*mLayerState));
+ // A buffer is not a unique field, but the assertions are the same.
+ verifyUniqueDifferingFields(*mLayerState, *otherLayerState);
// Buffers are explicitly excluded from comparison
EXPECT_FALSE(mLayerState->compare(*otherLayerState));
@@ -405,12 +402,7 @@
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop),
- otherLayerState->getDifferingFields(*mLayerState));
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SourceCrop);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -449,12 +441,7 @@
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder),
- otherLayerState->getDifferingFields(*mLayerState));
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::ZOrder);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -493,12 +480,8 @@
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform),
- otherLayerState->getDifferingFields(*mLayerState));
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState,
+ LayerStateField::BufferTransform);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -537,12 +520,7 @@
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode),
- otherLayerState->getDifferingFields(*mLayerState));
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::BlendMode);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -581,12 +559,46 @@
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::Alpha);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha),
- otherLayerState->getDifferingFields(*mLayerState));
+ EXPECT_TRUE(mLayerState->compare(*otherLayerState));
+ EXPECT_TRUE(otherLayerState->compare(*mLayerState));
+}
+
+TEST_F(LayerStateTest, updateLayerMetadata) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.metadata[sMetadataKeyOne] = sMetadataValueOne;
+ setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+
+ mock::OutputLayer newOutputLayer;
+ mock::LayerFE newLayerFE;
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo;
+ setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ layerFECompositionStateTwo);
+ Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(Flags<LayerStateField>(LayerStateField::LayerMetadata), updates);
+}
+
+TEST_F(LayerStateTest, compareLayerMetadata) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.metadata[sMetadataKeyOne] = sMetadataValueOne;
+ setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+ mock::OutputLayer newOutputLayer;
+ mock::LayerFE newLayerFE;
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo;
+ setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ layerFECompositionStateTwo);
+ auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
+
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::LayerMetadata);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -625,12 +637,7 @@
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion),
- otherLayerState->getDifferingFields(*mLayerState));
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::VisibleRegion);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -669,12 +676,65 @@
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::Dataspace);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace),
- otherLayerState->getDifferingFields(*mLayerState));
+ EXPECT_TRUE(mLayerState->compare(*otherLayerState));
+ EXPECT_TRUE(otherLayerState->compare(*mLayerState));
+}
+
+TEST_F(LayerStateTest, updatePixelFormat) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.buffer =
+ new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888,
+ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ "buffer1");
+ setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+
+ mock::OutputLayer newOutputLayer;
+ mock::LayerFE newLayerFE;
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.buffer =
+ new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888,
+ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ "buffer2");
+ setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ layerFECompositionStateTwo);
+ Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer) |
+ Flags<LayerStateField>(LayerStateField::PixelFormat),
+ updates);
+}
+
+TEST_F(LayerStateTest, comparePixelFormat) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.buffer =
+ new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888,
+ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ "buffer1");
+ setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+ mock::OutputLayer newOutputLayer;
+ mock::LayerFE newLayerFE;
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.buffer =
+ new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888,
+ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+ "buffer2");
+ setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ layerFECompositionStateTwo);
+ auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
+
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState,
+ Flags<LayerStateField>(LayerStateField::PixelFormat));
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -717,12 +777,48 @@
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::ColorTransform);
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform),
- otherLayerState->getDifferingFields(*mLayerState));
+ EXPECT_TRUE(mLayerState->compare(*otherLayerState));
+ EXPECT_TRUE(otherLayerState->compare(*mLayerState));
+}
+
+TEST_F(LayerStateTest, updateSurfaceDamage) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.surfaceDamage = sRegionOne;
+ setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+
+ mock::OutputLayer newOutputLayer;
+ mock::LayerFE newLayerFE;
+ OutputLayerCompositionState outputLayerCompositionStateTwo;
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.surfaceDamage = sRegionTwo;
+ setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SurfaceDamage), updates);
+}
+
+TEST_F(LayerStateTest, compareSurfaceDamage) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.surfaceDamage = sRegionOne;
+ setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+ mock::OutputLayer newOutputLayer;
+ mock::LayerFE newLayerFE;
+ OutputLayerCompositionState outputLayerCompositionStateTwo;
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.surfaceDamage = sRegionTwo;
+ setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
+
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SurfaceDamage);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -761,12 +857,7 @@
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream),
- otherLayerState->getDifferingFields(*mLayerState));
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SidebandStream);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -805,12 +896,7 @@
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
- EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
-
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor),
- mLayerState->getDifferingFields(*otherLayerState));
- EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor),
- otherLayerState->getDifferingFields(*mLayerState));
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SolidColor);
EXPECT_TRUE(mLayerState->compare(*otherLayerState));
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index f7fc162..8d685cf 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -76,14 +76,14 @@
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
- const auto limitedSize = limitFramebufferSize(size);
+ const auto limitedSize = limitSize(size);
mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
mConsumer->setMaxAcquiredBufferCount(
SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
}
void FramebufferSurface::resizeBuffers(const ui::Size& newSize) {
- const auto limitedSize = limitFramebufferSize(newSize);
+ const auto limitedSize = limitSize(newSize);
mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
}
@@ -179,19 +179,23 @@
}
}
-ui::Size FramebufferSurface::limitFramebufferSize(const ui::Size& size) {
+ui::Size FramebufferSurface::limitSize(const ui::Size& size) {
+ return limitSizeInternal(size, mMaxSize);
+}
+
+ui::Size FramebufferSurface::limitSizeInternal(const ui::Size& size, const ui::Size& maxSize) {
ui::Size limitedSize = size;
bool wasLimited = false;
- if (size.width > mMaxSize.width && mMaxSize.width != 0) {
+ if (size.width > maxSize.width && maxSize.width != 0) {
const float aspectRatio = static_cast<float>(size.width) / size.height;
- limitedSize.height = mMaxSize.width / aspectRatio;
- limitedSize.width = mMaxSize.width;
+ limitedSize.height = maxSize.width / aspectRatio;
+ limitedSize.width = maxSize.width;
wasLimited = true;
}
- if (size.height > mMaxSize.height && mMaxSize.height != 0) {
+ if (limitedSize.height > maxSize.height && maxSize.height != 0) {
const float aspectRatio = static_cast<float>(size.width) / size.height;
- limitedSize.height = mMaxSize.height;
- limitedSize.width = mMaxSize.height * aspectRatio;
+ limitedSize.height = maxSize.height;
+ limitedSize.width = maxSize.height * aspectRatio;
wasLimited = true;
}
ALOGI_IF(wasLimited, "framebuffer size has been limited to [%dx%d] from [%dx%d]",
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 5d1e131..3123351 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -55,15 +55,20 @@
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
private:
+ friend class FramebufferSurfaceTest;
+
+ // Limits the width and height by the maximum width specified.
+ ui::Size limitSize(const ui::Size&);
+
+ // Used for testing purposes.
+ static ui::Size limitSizeInternal(const ui::Size&, const ui::Size& maxSize);
+
virtual ~FramebufferSurface() { }; // this class cannot be overloaded
virtual void freeBufferLocked(int slotIndex);
virtual void dumpLocked(String8& result, const char* prefix) const;
- // Limits the width and height by the maximum width specified in the constructor.
- ui::Size limitFramebufferSize(const ui::Size&);
-
// nextBuffer waits for and then latches the next buffer from the
// BufferQueue and releases the previously latched buffer to the
// BufferQueue. The new buffer is returned in the 'buffer' argument.
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.cpp b/services/surfaceflinger/HdrLayerInfoReporter.cpp
new file mode 100644
index 0000000..c06e300
--- /dev/null
+++ b/services/surfaceflinger/HdrLayerInfoReporter.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "HdrLayerInfoReporter"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <utils/Trace.h>
+
+#include "HdrLayerInfoReporter.h"
+
+namespace android {
+
+void HdrLayerInfoReporter::dispatchHdrLayerInfo(const HdrLayerInfo& info) {
+ ATRACE_CALL();
+ std::vector<sp<gui::IHdrLayerInfoListener>> toInvoke;
+ {
+ std::scoped_lock lock(mMutex);
+ toInvoke.reserve(mListeners.size());
+ for (auto& [key, it] : mListeners) {
+ if (it.lastInfo != info) {
+ it.lastInfo = info;
+ toInvoke.push_back(it.listener);
+ }
+ }
+ }
+
+ for (const auto& listener : toInvoke) {
+ ATRACE_NAME("invoking onHdrLayerInfoChanged");
+ listener->onHdrLayerInfoChanged(info.numberOfHdrLayers, info.maxW, info.maxH, info.flags);
+ }
+}
+
+void HdrLayerInfoReporter::binderDied(const wp<IBinder>& who) {
+ std::scoped_lock lock(mMutex);
+ mListeners.erase(who);
+}
+
+void HdrLayerInfoReporter::addListener(const sp<gui::IHdrLayerInfoListener>& listener) {
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+ asBinder->linkToDeath(this);
+ std::lock_guard lock(mMutex);
+ mListeners.emplace(wp<IBinder>(asBinder), TrackedListener{listener, HdrLayerInfo{}});
+}
+
+void HdrLayerInfoReporter::removeListener(const sp<gui::IHdrLayerInfoListener>& listener) {
+ std::lock_guard lock(mMutex);
+ mListeners.erase(wp<IBinder>(IInterface::asBinder(listener)));
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.h b/services/surfaceflinger/HdrLayerInfoReporter.h
new file mode 100644
index 0000000..671395f
--- /dev/null
+++ b/services/surfaceflinger/HdrLayerInfoReporter.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <android/gui/IHdrLayerInfoListener.h>
+#include <binder/IBinder.h>
+
+#include <unordered_map>
+
+namespace android {
+
+class HdrLayerInfoReporter final : public IBinder::DeathRecipient {
+public:
+ struct HdrLayerInfo {
+ int32_t numberOfHdrLayers = 0;
+ int32_t maxW = 0;
+ int32_t maxH = 0;
+ int32_t flags = 0;
+
+ bool operator==(const HdrLayerInfo& other) const {
+ return numberOfHdrLayers == other.numberOfHdrLayers && maxW == other.maxW &&
+ maxH == other.maxH && flags == other.flags;
+ }
+
+ bool operator!=(const HdrLayerInfo& other) const { return !(*this == other); }
+ };
+
+ HdrLayerInfoReporter() = default;
+ ~HdrLayerInfoReporter() final = default;
+
+ // Dispatches updated layer fps values for the registered listeners
+ // This method promotes Layer weak pointers and performs layer stack traversals, so mStateLock
+ // must be held when calling this method.
+ void dispatchHdrLayerInfo(const HdrLayerInfo& info) EXCLUDES(mMutex);
+
+ // Override for IBinder::DeathRecipient
+ void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
+
+ // Registers an Fps listener that listens to fps updates for the provided layer
+ void addListener(const sp<gui::IHdrLayerInfoListener>& listener) EXCLUDES(mMutex);
+ // Deregisters an Fps listener
+ void removeListener(const sp<gui::IHdrLayerInfoListener>& listener) EXCLUDES(mMutex);
+
+ bool hasListeners() const EXCLUDES(mMutex) {
+ std::scoped_lock lock(mMutex);
+ return !mListeners.empty();
+ }
+
+private:
+ mutable std::mutex mMutex;
+ struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const {
+ return std::hash<IBinder*>()(p.unsafe_get());
+ }
+ };
+
+ struct TrackedListener {
+ sp<gui::IHdrLayerInfoListener> listener;
+ HdrLayerInfo lastInfo;
+ };
+
+ std::unordered_map<wp<IBinder>, TrackedListener, WpHash> mListeners GUARDED_BY(mMutex);
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f7c9291..8aa60a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -112,6 +112,7 @@
#include "FpsReporter.h"
#include "FrameTimeline/FrameTimeline.h"
#include "FrameTracer/FrameTracer.h"
+#include "HdrLayerInfoReporter.h"
#include "Layer.h"
#include "LayerRenderArea.h"
#include "LayerVector.h"
@@ -285,6 +286,7 @@
const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER");
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
+const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS");
const String16 sDump("android.permission.DUMP");
const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
@@ -753,6 +755,8 @@
getRenderEngine().primeCache();
}
+ getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize());
+
// Inform native graphics APIs whether the present timestamp is supported:
const bool presentFenceReliable =
@@ -1492,6 +1496,47 @@
.get();
}
+status_t SurfaceFlinger::addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) {
+ if (!displayToken) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+ const auto displayId = display->getId();
+ sp<HdrLayerInfoReporter>& hdrInfoReporter = mHdrLayerInfoListeners[displayId];
+ if (!hdrInfoReporter) {
+ hdrInfoReporter = sp<HdrLayerInfoReporter>::make();
+ }
+ hdrInfoReporter->addListener(listener);
+ return OK;
+}
+
+status_t SurfaceFlinger::removeHdrLayerInfoListener(
+ const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+ if (!displayToken) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+ const auto displayId = display->getId();
+ sp<HdrLayerInfoReporter>& hdrInfoReporter = mHdrLayerInfoListeners[displayId];
+ if (hdrInfoReporter) {
+ hdrInfoReporter->removeListener(listener);
+ }
+ return OK;
+}
+
status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) {
Boost powerBoost = static_cast<Boost>(boostId);
@@ -2155,11 +2200,58 @@
}
});
+ std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>>
+ hdrInfoListeners;
{
Mutex::Autolock lock(mStateLock);
if (mFpsReporter) {
mFpsReporter->dispatchLayerFps();
}
+ hdrInfoListeners.reserve(mHdrLayerInfoListeners.size());
+ for (auto& [key, value] : mHdrLayerInfoListeners) {
+ if (value && value->hasListeners()) {
+ auto listenersDisplay = getDisplayById(key);
+ if (listenersDisplay) {
+ hdrInfoListeners.emplace_back(listenersDisplay->getCompositionDisplay(), value);
+ }
+ }
+ }
+ }
+
+ for (auto& [compositionDisplay, listener] : hdrInfoListeners) {
+ HdrLayerInfoReporter::HdrLayerInfo info;
+ int32_t maxArea = 0;
+ mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
+ if (layer->isVisible() &&
+ compositionDisplay->belongsInOutput(layer->getCompositionEngineLayerFE())) {
+ bool isHdr = false;
+ switch (layer->getDataSpace()) {
+ case ui::Dataspace::BT2020:
+ case ui::Dataspace::BT2020_HLG:
+ case ui::Dataspace::BT2020_PQ:
+ case ui::Dataspace::BT2020_ITU:
+ case ui::Dataspace::BT2020_ITU_HLG:
+ case ui::Dataspace::BT2020_ITU_PQ:
+ isHdr = true;
+ break;
+ default:
+ isHdr = false;
+ break;
+ }
+
+ if (isHdr) {
+ info.numberOfHdrLayers++;
+ auto bufferRect = layer->getCompositionState()->geomBufferSize;
+ int32_t area = bufferRect.width() * bufferRect.height();
+ if (area > maxArea) {
+ maxArea = area;
+ info.maxW = bufferRect.width();
+ info.maxH = bufferRect.height();
+ }
+ }
+ }
+ });
+ listener->dispatchHdrLayerInfo(info);
}
mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0]);
@@ -2634,6 +2726,7 @@
if (display->isPrimary()) {
mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight());
+ getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize());
}
}
@@ -5113,6 +5206,20 @@
// This is not sensitive information, so should not require permission control.
return OK;
}
+ case ADD_HDR_LAYER_INFO_LISTENER:
+ case REMOVE_HDR_LAYER_INFO_LISTENER: {
+ // TODO (b/183985553): Should getting & setting brightness be part of this...?
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) &&
+ !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
+ ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
case ADD_FPS_LISTENER:
case REMOVE_FPS_LISTENER:
case ADD_REGION_SAMPLING_LISTENER:
@@ -5674,6 +5781,15 @@
return getDisplayByLayerStack(displayOrLayerStack);
}
+sp<DisplayDevice> SurfaceFlinger::getDisplayById(DisplayId displayId) const {
+ for (const auto& [token, display] : mDisplays) {
+ if (display->getId() == displayId) {
+ return display;
+ }
+ }
+ return nullptr;
+}
+
sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
for (const auto& [token, display] : mDisplays) {
if (display->getLayerStack() == layerStack) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c57b180..2b97f34 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -90,6 +90,7 @@
class Client;
class EventThread;
class FpsReporter;
+class HdrLayerInfoReporter;
class HWComposer;
struct SetInputWindowsListener;
class IGraphicBufferProducer;
@@ -684,6 +685,10 @@
bool* outSupport) const override;
status_t setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) override;
+ status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
+ status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
+ const sp<gui::IHdrLayerInfoListener>& listener) override;
status_t notifyPowerBoost(int32_t boostId) override;
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
@@ -908,6 +913,7 @@
bool grayscale, ScreenCaptureResults&);
sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
+ sp<DisplayDevice> getDisplayById(DisplayId displayId) const REQUIRES(mStateLock);
sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
// If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a
@@ -1386,6 +1392,9 @@
sp<IBinder> mDebugFrameRateFlexibilityToken;
BufferCountTracker mBufferCountTracker;
+
+ std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners
+ GUARDED_BY(mStateLock);
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 3c1b9d8..9f94c73 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -55,6 +55,7 @@
"EventThreadTest.cpp",
"FpsReporterTest.cpp",
"FpsTest.cpp",
+ "FramebufferSurfaceTest.cpp",
"FrameTimelineTest.cpp",
"HWComposerTest.cpp",
"OneShotTimerTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp b/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp
new file mode 100644
index 0000000..b8df640
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DisplayHardware/FramebufferSurface.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+class FramebufferSurfaceTest : public testing::Test {
+public:
+ ui::Size limitSize(const ui::Size& size, const ui::Size maxSize) {
+ return FramebufferSurface::limitSizeInternal(size, maxSize);
+ }
+};
+
+TEST_F(FramebufferSurfaceTest, limitSize) {
+ const ui::Size kMaxSize(1920, 1080);
+ EXPECT_EQ(ui::Size(1920, 1080), limitSize({3840, 2160}, kMaxSize));
+ EXPECT_EQ(ui::Size(1920, 1080), limitSize({1920, 1080}, kMaxSize));
+ EXPECT_EQ(ui::Size(1920, 1012), limitSize({4096, 2160}, kMaxSize));
+ EXPECT_EQ(ui::Size(1080, 1080), limitSize({3840, 3840}, kMaxSize));
+ EXPECT_EQ(ui::Size(1280, 720), limitSize({1280, 720}, kMaxSize));
+}
+
+} // namespace android
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 866007e..eb24a22 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -108,6 +108,7 @@
cc_binary {
name: "vr_hwc",
+ enabled: false,
system_ext_specific: true,
vintf_fragments: ["manifest_vr_hwc.xml"],
srcs: [
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index eb0fcc3..5872495 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -363,6 +363,10 @@
VkJsonDeviceGroup device_group;
std::vector<VkPhysicalDeviceGroupProperties> group_properties;
group_properties.resize(count);
+ for (auto& properties : group_properties) {
+ properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
+ properties.pNext = nullptr;
+ }
result = vkEnumeratePhysicalDeviceGroups(vkinstance, &count,
group_properties.data());
if (result != VK_SUCCESS) {