Merge "Add a warning to the atrace binary for deprecating vendor categories"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 1c3a4f2..a417493 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -292,12 +292,9 @@
write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
-# Set up histogram triggers
- # rss_stat_throttled (bucket size == 512KB)
- chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+ # allow creating event triggers
chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
- write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
- write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+ chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
# Only create the tracing instance if persist.mm_events.enabled
# Attempting to remove the tracing instance after it has been created
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index a2491e5..a60972b 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -101,6 +101,7 @@
"libhidlbase",
"liblog",
"libutils",
+ "libvintf",
"libbinderdebug",
"packagemanager_aidl-cpp",
],
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0dab0e4..942a17e 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -88,6 +88,7 @@
#include <private/android_logger.h>
#include <serviceutils/PriorityDumper.h>
#include <utils/StrongPointer.h>
+#include <vintf/VintfObject.h>
#include "DumpstateInternal.h"
#include "DumpstateService.h"
#include "dumpstate.h"
@@ -1396,6 +1397,23 @@
}
}
+// Dump all of the files that make up the vendor interface.
+// See the files listed in dumpFileList() for the latest list of files.
+static void DumpVintf() {
+ const auto vintfFiles = android::vintf::details::dumpFileList();
+ for (const auto vintfFile : vintfFiles) {
+ struct stat st;
+ if (stat(vintfFile.c_str(), &st) == 0) {
+ if (S_ISDIR(st.st_mode)) {
+ ds.AddDir(vintfFile, true /* recursive */);
+ } else {
+ ds.EnqueueAddZipEntryAndCleanupIfNeeded(ZIP_ROOT_DIR + vintfFile,
+ vintfFile);
+ }
+ }
+ }
+}
+
static void DumpExternalFragmentationInfo() {
struct stat st;
if (stat("/proc/buddyinfo", &st) != 0) {
@@ -1621,6 +1639,8 @@
do_dmesg();
}
+ DumpVintf();
+
RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
@@ -2086,7 +2106,7 @@
int timeout_failures = 0;
bool dalvik_found = false;
- const std::set<int> hal_pids = get_interesting_hal_pids();
+ const std::set<int> hal_pids = get_interesting_pids();
struct dirent* d;
while ((d = readdir(proc.get()))) {
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 49c1318..f0c19b9 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -65,6 +65,7 @@
const sp<LocalRegistrationCallback>&));
MOCK_METHOD2(unregisterForNotifications, status_t(const String16&,
const sp<LocalRegistrationCallback>&));
+ MOCK_METHOD0(getServiceDebugInfo, std::vector<ServiceDebugInfo>());
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 7f0324a..22b9faa 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -295,6 +295,8 @@
/*
* Gets the path of an input device configuration file, if one is available.
* Considers both system provided and user installed configuration files.
+ * The optional suffix is appended to the end of the file name (before the
+ * extension).
*
* The device identifier is used to construct several default configuration file
* names to try based on the device name, vendor, product, and version.
@@ -302,8 +304,8 @@
* Returns an empty string if not found.
*/
extern std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
- const InputDeviceIdentifier& deviceIdentifier,
- InputDeviceConfigurationFileType type);
+ const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type,
+ const char* suffix = "");
/*
* Gets the path of an input device configuration file, if one is available.
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index b2bd535..1da78aa 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -20,9 +20,8 @@
#include <android-base/result.h>
#include <stdint.h>
#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
#include <utils/Tokenizer.h>
+#include <set>
#include <input/InputDevice.h>
@@ -65,18 +64,18 @@
*/
class KeyLayoutMap {
public:
- static base::Result<std::shared_ptr<KeyLayoutMap>> load(const std::string& filename);
- static base::Result<std::shared_ptr<KeyLayoutMap>> load(Tokenizer* tokenizer);
+ static base::Result<std::shared_ptr<KeyLayoutMap>> load(const std::string& filename,
+ const char* contents = nullptr);
static base::Result<std::shared_ptr<KeyLayoutMap>> loadContents(const std::string& filename,
const char* contents);
status_t mapKey(int32_t scanCode, int32_t usageCode,
int32_t* outKeyCode, uint32_t* outFlags) const;
- status_t findScanCodesForKey(int32_t keyCode, std::vector<int32_t>* outScanCodes) const;
- status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const;
- status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const;
+ std::vector<int32_t> findScanCodesForKey(int32_t keyCode) const;
+ std::optional<int32_t> findScanCodeForLed(int32_t ledCode) const;
+ std::optional<int32_t> findUsageCodeForLed(int32_t ledCode) const;
- status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
+ std::optional<AxisInfo> mapAxis(int32_t scanCode) const;
const std::string getLoadFileName() const;
// Return pair of sensor type and sensor data index, for the input device abs code
base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode);
@@ -84,6 +83,8 @@
virtual ~KeyLayoutMap();
private:
+ static base::Result<std::shared_ptr<KeyLayoutMap>> load(Tokenizer* tokenizer);
+
struct Key {
int32_t keyCode;
uint32_t flags;
@@ -98,12 +99,13 @@
int32_t sensorDataIndex;
};
- KeyedVector<int32_t, Key> mKeysByScanCode;
- KeyedVector<int32_t, Key> mKeysByUsageCode;
- KeyedVector<int32_t, AxisInfo> mAxes;
- KeyedVector<int32_t, Led> mLedsByScanCode;
- KeyedVector<int32_t, Led> mLedsByUsageCode;
+ std::unordered_map<int32_t, Key> mKeysByScanCode;
+ std::unordered_map<int32_t, Key> mKeysByUsageCode;
+ std::unordered_map<int32_t, AxisInfo> mAxes;
+ std::unordered_map<int32_t, Led> mLedsByScanCode;
+ std::unordered_map<int32_t, Led> mLedsByUsageCode;
std::unordered_map<int32_t, Sensor> mSensorsByAbsCode;
+ std::set<std::string> mRequiredKernelConfigs;
std::string mLoadFileName;
KeyLayoutMap();
@@ -124,6 +126,7 @@
status_t parseAxis();
status_t parseLed();
status_t parseSensor();
+ status_t parseRequiredKernelConfig();
};
};
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 08ad8c6..9a3e15f 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -61,9 +61,7 @@
bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
- const std::string& name);
- std::string getPath(const InputDeviceIdentifier& deviceIdentifier,
- const std::string& name, InputDeviceConfigurationFileType type);
+ const std::string& name);
};
/**
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 21d98e0..9389bec 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -60,11 +60,15 @@
//
// Currently, these are only on system android (not vendor, not host)
// TODO(b/183654927) - move these into separate libraries
-libbinder_device_interface_sources = [
- "IPermissionController.cpp",
- "PermissionCache.cpp",
- "PermissionController.cpp",
-]
+
+filegroup {
+ name: "libbinder_device_interface_sources",
+ srcs: [
+ "IPermissionController.cpp",
+ "PermissionCache.cpp",
+ "PermissionController.cpp",
+ ],
+}
cc_library {
name: "libbinder",
@@ -126,19 +130,20 @@
"TextOutput.cpp",
"Utils.cpp",
":libbinder_aidl",
+ ":libbinder_device_interface_sources",
],
target: {
android: {
- srcs: libbinder_device_interface_sources,
-
// NOT static to keep the wire protocol unfrozen
static: {
enabled: false,
},
},
vendor: {
- exclude_srcs: libbinder_device_interface_sources,
+ exclude_srcs: [
+ ":libbinder_device_interface_sources",
+ ],
},
darwin: {
enabled: false,
@@ -216,6 +221,7 @@
"abseil-*",
"android-*",
"bugprone-*",
+ "-bugprone-branch-clone", // b/155034972
"cert-*",
"clang-analyzer-*",
"google-*",
@@ -365,6 +371,7 @@
cc_library {
name: "libbatterystats_aidl",
+ host_supported: true,
srcs: [
"IBatteryStats.cpp",
],
@@ -377,6 +384,7 @@
cc_library {
name: "libprocessinfoservice_aidl",
+ host_supported: true,
srcs: [
"IProcessInfoService.cpp",
"ProcessInfoService.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 6a12e65..e2db1a3 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -32,9 +32,12 @@
#include <utils/misc.h>
#include <inttypes.h>
-#include <linux/sched.h>
#include <stdio.h>
+#ifdef __linux__
+#include <linux/sched.h>
+#endif
+
#include "RpcState.h"
namespace android {
@@ -234,11 +237,13 @@
{
public:
// unlocked objects
- bool mRequestingSid = false;
- bool mInheritRt = false;
sp<IBinder> mExtension;
+#ifdef __linux__
int mPolicy = SCHED_NORMAL;
int mPriority = 0;
+#endif
+ bool mRequestingSid = false;
+ bool mInheritRt = false;
// for below objects
Mutex mLock;
@@ -407,6 +412,7 @@
return e->mExtension;
}
+#ifdef __linux__
void BBinder::setMinSchedulerPolicy(int policy, int priority) {
LOG_ALWAYS_FATAL_IF(mParceled,
"setMinSchedulerPolicy() should not be called after a binder object "
@@ -451,6 +457,7 @@
if (e == nullptr) return 0;
return e->mPriority;
}
+#endif // __linux__
bool BBinder::isInheritRt() {
Extras* e = mExtras.load(std::memory_order_acquire);
@@ -478,7 +485,12 @@
}
pid_t BBinder::getDebugPid() {
+#ifdef __linux__
return getpid();
+#else
+ // TODO: handle other OSes
+ return 0;
+#endif // __linux__
}
void BBinder::setExtension(const sp<IBinder>& extension) {
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ea2f8d2..fd47783 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -99,6 +99,8 @@
status_t unregisterForNotifications(const String16& service,
const sp<AidlRegistrationCallback>& cb) override;
+
+ std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
return mTheRealServiceManager->getInterfaceDescriptor();
@@ -165,7 +167,7 @@
}
}
-#if !defined(__ANDROID_VNDK__) && defined(__ANDROID__)
+#if !defined(__ANDROID_VNDK__)
// IPermissionController is not accessible to vendors
bool checkCallingPermission(const String16& permission)
@@ -543,6 +545,23 @@
return OK;
}
+std::vector<IServiceManager::ServiceDebugInfo> ServiceManagerShim::getServiceDebugInfo() {
+ std::vector<os::ServiceDebugInfo> serviceDebugInfos;
+ std::vector<IServiceManager::ServiceDebugInfo> ret;
+ if (Status status = mTheRealServiceManager->getServiceDebugInfo(&serviceDebugInfos);
+ !status.isOk()) {
+ ALOGW("%s Failed to get ServiceDebugInfo", __FUNCTION__);
+ return ret;
+ }
+ for (const auto& serviceDebugInfo : serviceDebugInfos) {
+ IServiceManager::ServiceDebugInfo retInfo;
+ retInfo.pid = serviceDebugInfo.debugPid;
+ retInfo.name = serviceDebugInfo.name;
+ ret.emplace_back(retInfo);
+ }
+ return ret;
+}
+
#ifndef __ANDROID__
// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
// The internal implementation of the AIDL interface android::os::IServiceManager calls into
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 038ce38..e67dd7b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -87,7 +87,8 @@
static std::atomic<size_t> gParcelGlobalAllocCount;
static std::atomic<size_t> gParcelGlobalAllocSize;
-static size_t gMaxFds = 0;
+// Maximum number of file descriptors per Parcel.
+constexpr size_t kMaxFds = 1024;
// Maximum size of a blob to transfer in-place.
static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
@@ -1416,7 +1417,7 @@
const size_t len = val.getFlattenedSize();
const size_t fd_count = val.getFdCount();
- if ((len > INT32_MAX) || (fd_count >= gMaxFds)) {
+ if ((len > INT32_MAX) || (fd_count > kMaxFds)) {
// don't accept size_t values which may have come from an
// inadvertent conversion from a negative int.
return BAD_VALUE;
@@ -2158,7 +2159,7 @@
const size_t len = this->readInt32();
const size_t fd_count = this->readInt32();
- if ((len > INT32_MAX) || (fd_count >= gMaxFds)) {
+ if ((len > INT32_MAX) || (fd_count > kMaxFds)) {
// don't accept size_t values which may have come from an
// inadvertent conversion from a negative int.
return BAD_VALUE;
@@ -2747,18 +2748,6 @@
mAllowFds = true;
mDeallocZero = false;
mOwner = nullptr;
-
- // racing multiple init leads only to multiple identical write
- if (gMaxFds == 0) {
- struct rlimit result;
- if (!getrlimit(RLIMIT_NOFILE, &result)) {
- gMaxFds = (size_t)result.rlim_cur;
- //ALOGI("parcel fd limit set to %zu", gMaxFds);
- } else {
- ALOGW("Unable to getrlimit: %s", strerror(errno));
- gMaxFds = 1024;
- }
- }
}
void Parcel::scanForFds() const {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index c67b70a..528341e 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -135,7 +135,7 @@
mRootObjectWeak = binder;
}
void RpcServer::setPerSessionRootObject(
- std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& makeObject) {
+ std::function<sp<IBinder>(const void*, size_t)>&& makeObject) {
std::lock_guard<std::mutex> _l(mLock);
mRootObject.clear();
mRootObjectWeak.clear();
@@ -178,14 +178,16 @@
status_t status;
while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
- sockaddr_storage addr;
- socklen_t addrLen = sizeof(addr);
+ std::array<uint8_t, kRpcAddressSize> addr;
+ static_assert(addr.size() >= sizeof(sockaddr_storage), "kRpcAddressSize is too small");
+ socklen_t addrLen = addr.size();
unique_fd clientFd(
- TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(&addr),
+ TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(addr.data()),
&addrLen, SOCK_CLOEXEC | SOCK_NONBLOCK)));
- LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(addr)), "Truncated address");
+ LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(sockaddr_storage)),
+ "Truncated address");
if (clientFd < 0) {
ALOGE("Could not accept4 socket: %s", strerror(errno));
@@ -268,7 +270,7 @@
}
void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
- const sockaddr_storage addr, socklen_t addrLen) {
+ std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen) {
// mShutdownTrigger can only be cleared once connection threads have joined.
// It must be set before this thread is started
LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
@@ -390,16 +392,14 @@
}
} while (server->mSessions.end() != server->mSessions.find(sessionId));
- session = RpcSession::make();
+ session = sp<RpcSession>::make(nullptr);
session->setMaxIncomingThreads(server->mMaxThreads);
if (!session->setProtocolVersion(protocolVersion)) return;
// if null, falls back to server root
sp<IBinder> sessionSpecificRoot;
if (server->mRootObjectFactory != nullptr) {
- sessionSpecificRoot =
- server->mRootObjectFactory(reinterpret_cast<const sockaddr*>(&addr),
- addrLen);
+ sessionSpecificRoot = server->mRootObjectFactory(addr.data(), addrLen);
if (sessionSpecificRoot == nullptr) {
ALOGE("Warning: server returned null from root object factory");
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 5c35dd0..7ba08ed 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -699,10 +699,7 @@
mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
}
- {
- std::lock_guard<std::mutex> _l(mMutex);
- connection->exclusiveTid = std::nullopt;
- }
+ clearConnectionTid(connection);
return status;
}
@@ -715,6 +712,7 @@
LOG_ALWAYS_FATAL_IF(mEventListener != nullptr);
LOG_ALWAYS_FATAL_IF(eventListener == nullptr);
LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr);
+ LOG_ALWAYS_FATAL_IF(mCtx != nullptr);
mShutdownTrigger = FdTrigger::make();
if (mShutdownTrigger == nullptr) return false;
@@ -772,6 +770,15 @@
return false;
}
+void RpcSession::clearConnectionTid(const sp<RpcConnection>& connection) {
+ std::unique_lock<std::mutex> _l(mMutex);
+ connection->exclusiveTid = std::nullopt;
+ if (mConnections.mWaitingThreads > 0) {
+ _l.unlock();
+ mAvailableConnectionCv.notify_one();
+ }
+}
+
std::vector<uint8_t> RpcSession::getCertificate(RpcCertificateFormat format) {
return mCtx->getCertificate(format);
}
@@ -901,12 +908,7 @@
// is using this fd, and it retains the right to it. So, we don't give up
// exclusive ownership, and no thread is freed.
if (!mReentrant && mConnection != nullptr) {
- std::unique_lock<std::mutex> _l(mSession->mMutex);
- mConnection->exclusiveTid = std::nullopt;
- if (mSession->mConnections.mWaitingThreads > 0) {
- _l.unlock();
- mSession->mAvailableConnectionCv.notify_one();
- }
+ mSession->clearConnectionTid(mConnection);
}
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 7ec8e07..419df86 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -27,6 +27,7 @@
#include "Debug.h"
#include "RpcWireFormat.h"
+#include "Utils.h"
#include <random>
@@ -493,9 +494,15 @@
}
}
+ // objectTable always empty for now. Will be populated from `data` soon.
+ std::vector<uint32_t> objectTable;
+ Span<const uint32_t> objectTableSpan = {objectTable.data(), objectTable.size()};
+
uint32_t bodySize;
LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireTransaction), data.dataSize(),
- &bodySize),
+ &bodySize) ||
+ __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
+ &bodySize),
"Too much data %zu", data.dataSize());
RpcWireHeader command{
.command = RPC_COMMAND_TRANSACT,
@@ -507,6 +514,8 @@
.code = code,
.flags = flags,
.asyncNumber = asyncNumber,
+ // bodySize didn't overflow => this cast is safe
+ .parcelDataSize = static_cast<uint32_t>(data.dataSize()),
};
constexpr size_t kWaitMaxUs = 1000000;
@@ -521,6 +530,7 @@
{&command, sizeof(RpcWireHeader)},
{&transaction, sizeof(RpcWireTransaction)},
{const_cast<uint8_t*>(data.data()), data.dataSize()},
+ objectTableSpan.toIovec(),
};
if (status_t status = rpcSend(connection, session, "transaction", iovs, arraysize(iovs),
[&] {
@@ -563,7 +573,7 @@
static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize,
const binder_size_t* objects, size_t objectsCount) {
(void)p;
- delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data));
+ delete[] const_cast<uint8_t*>(data);
(void)dataSize;
LOG_ALWAYS_FATAL_IF(objects != nullptr);
LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
@@ -585,26 +595,39 @@
return status;
}
- CommandData data(command.bodySize);
- if (!data.valid()) return NO_MEMORY;
+ const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
- iovec iov{data.data(), command.bodySize};
- if (status_t status = rpcRec(connection, session, "reply body", &iov, 1); status != OK)
- return status;
-
- if (command.bodySize < sizeof(RpcWireReply)) {
+ if (command.bodySize < rpcReplyWireSize) {
ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!",
sizeof(RpcWireReply), command.bodySize);
(void)session->shutdownAndWait(false);
return BAD_VALUE;
}
- RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data.data());
- if (rpcReply->status != OK) return rpcReply->status;
+
+ RpcWireReply rpcReply;
+ memset(&rpcReply, 0, sizeof(RpcWireReply)); // zero because of potential short read
+
+ CommandData data(command.bodySize - rpcReplyWireSize);
+ if (!data.valid()) return NO_MEMORY;
+
+ iovec iovs[]{
+ {&rpcReply, rpcReplyWireSize},
+ {data.data(), data.size()},
+ };
+ if (status_t status = rpcRec(connection, session, "reply body", iovs, arraysize(iovs));
+ status != OK)
+ return status;
+ if (rpcReply.status != OK) return rpcReply.status;
+
+ Span<const uint8_t> parcelSpan = {data.data(), data.size()};
+ if (session->getProtocolVersion().value() >=
+ RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
+ Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
+ LOG_ALWAYS_FATAL_IF(objectTableBytes.size > 0, "Non-empty object table not supported yet.");
+ }
data.release();
- reply->rpcSetDataReference(session, rpcReply->data,
- command.bodySize - offsetof(RpcWireReply, data), cleanup_reply_data);
-
+ reply->rpcSetDataReference(session, parcelSpan.data, parcelSpan.size, cleanup_reply_data);
return OK;
}
@@ -819,12 +842,22 @@
reply.markForRpc(session);
if (replyStatus == OK) {
+ Span<const uint8_t> parcelSpan = {transaction->data,
+ transactionData.size() -
+ offsetof(RpcWireTransaction, data)};
+ if (session->getProtocolVersion().value() >=
+ RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
+ Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
+ LOG_ALWAYS_FATAL_IF(objectTableBytes.size > 0,
+ "Non-empty object table not supported yet.");
+ }
+
Parcel data;
// transaction->data is owned by this function. Parcel borrows this data and
// only holds onto it for the duration of this function call. Parcel will be
// deleted before the 'transactionData' object.
- data.rpcSetDataReference(session, transaction->data,
- transactionData.size() - offsetof(RpcWireTransaction, data),
+
+ data.rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
do_nothing_to_transact_data);
if (target) {
@@ -936,8 +969,16 @@
replyStatus = flushExcessBinderRefs(session, addr, target);
}
+ const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
+
+ // objectTable always empty for now. Will be populated from `reply` soon.
+ std::vector<uint32_t> objectTable;
+ Span<const uint32_t> objectTableSpan = {objectTable.data(), objectTable.size()};
+
uint32_t bodySize;
- LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireReply), reply.dataSize(), &bodySize),
+ LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(rpcReplyWireSize, reply.dataSize(), &bodySize) ||
+ __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
+ &bodySize),
"Too much data for reply %zu", reply.dataSize());
RpcWireHeader cmdReply{
.command = RPC_COMMAND_REPLY,
@@ -945,12 +986,17 @@
};
RpcWireReply rpcReply{
.status = replyStatus,
+ // NOTE: Not necessarily written to socket depending on session
+ // version.
+ // NOTE: bodySize didn't overflow => this cast is safe
+ .parcelDataSize = static_cast<uint32_t>(reply.dataSize()),
+ .reserved = {0, 0, 0},
};
-
iovec iovs[]{
{&cmdReply, sizeof(RpcWireHeader)},
- {&rpcReply, sizeof(RpcWireReply)},
+ {&rpcReply, rpcReplyWireSize},
{const_cast<uint8_t*>(reply.data()), reply.dataSize()},
+ objectTableSpan.toIovec(),
};
return rpcSend(connection, session, "reply", iovs, arraysize(iovs), std::nullopt);
}
@@ -959,23 +1005,19 @@
const sp<RpcSession>& session, const RpcWireHeader& command) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
- CommandData commandData(command.bodySize);
- if (!commandData.valid()) {
- return NO_MEMORY;
- }
- iovec iov{commandData.data(), commandData.size()};
- if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK)
- return status;
-
if (command.bodySize != sizeof(RpcDecStrong)) {
ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcDecStrong. Terminating!",
sizeof(RpcDecStrong), command.bodySize);
(void)session->shutdownAndWait(false);
return BAD_VALUE;
}
- RpcDecStrong* body = reinterpret_cast<RpcDecStrong*>(commandData.data());
- uint64_t addr = RpcWireAddress::toRaw(body->address);
+ RpcDecStrong body;
+ iovec iov{&body, sizeof(RpcDecStrong)};
+ if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK)
+ return status;
+
+ uint64_t addr = RpcWireAddress::toRaw(body.address);
std::unique_lock<std::mutex> _l(mNodeMutex);
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
@@ -993,19 +1035,19 @@
return BAD_VALUE;
}
- if (it->second.timesSent < body->amount) {
+ if (it->second.timesSent < body.amount) {
ALOGE("Record of sending binder %zu times, but requested decStrong for %" PRIu64 " of %u",
- it->second.timesSent, addr, body->amount);
+ it->second.timesSent, addr, body.amount);
return OK;
}
LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %" PRIu64,
addr);
- LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body->amount,
+ LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body.amount,
it->second.timesSent);
- it->second.timesSent -= body->amount;
+ it->second.timesSent -= body.amount;
sp<IBinder> tempHold = tryEraseNode(it);
_l.unlock();
tempHold = nullptr; // destructor may make binder calls on this session
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 171550e..7e2aa79 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -131,7 +131,10 @@
uint64_t asyncNumber;
- uint32_t reserved[4];
+ // The size of the Parcel data directly following RpcWireTransaction.
+ uint32_t parcelDataSize;
+
+ uint32_t reserved[3];
uint8_t data[];
};
@@ -139,9 +142,23 @@
struct RpcWireReply {
int32_t status; // transact return
- uint8_t data[];
+
+ // -- Fields below only transmitted starting at protocol version 1 --
+
+ // The size of the Parcel data directly following RpcWireReply.
+ uint32_t parcelDataSize;
+
+ uint32_t reserved[3];
+
+ // Byte size of RpcWireReply in the wire protocol.
+ static size_t wireSize(uint32_t protocolVersion) {
+ if (protocolVersion == 0) {
+ return sizeof(int32_t);
+ }
+ return sizeof(RpcWireReply);
+ }
};
-static_assert(sizeof(RpcWireReply) == 4);
+static_assert(sizeof(RpcWireReply) == 20);
#pragma clang diagnostic pop
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 83b97d0..dba6587 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -139,6 +139,9 @@
mMessage = String8(message.value_or(String16()));
// Skip over the remote stack trace data
+ const size_t remote_start = parcel.dataPosition();
+ // Get available size before reading more
+ const size_t remote_avail = parcel.dataAvail();
int32_t remote_stack_trace_header_size;
status = parcel.readInt32(&remote_stack_trace_header_size);
if (status != OK) {
@@ -146,13 +149,16 @@
return status;
}
if (remote_stack_trace_header_size < 0 ||
- static_cast<size_t>(remote_stack_trace_header_size) > parcel.dataAvail()) {
+ static_cast<size_t>(remote_stack_trace_header_size) > remote_avail) {
android_errorWriteLog(0x534e4554, "132650049");
setFromStatusT(UNKNOWN_ERROR);
return UNKNOWN_ERROR;
}
- parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size);
+
+ if (remote_stack_trace_header_size != 0) {
+ parcel.setDataPosition(remote_start + remote_stack_trace_header_size);
+ }
if (mException == EX_SERVICE_SPECIFIC) {
status = parcel.readInt32(&mErrorCode);
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index 150d520..7dcb70e 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include <cstdint>
#include <stddef.h>
+#include <cstdint>
+#include <optional>
#include <android-base/result.h>
#include <android-base/unique_fd.h>
@@ -39,4 +40,26 @@
status_t getRandomBytes(uint8_t* data, size_t size);
+// View of contiguous sequence. Similar to std::span.
+template <typename T>
+struct Span {
+ T* data = nullptr;
+ size_t size = 0;
+
+ size_t byteSize() { return size * sizeof(T); }
+
+ iovec toIovec() { return {const_cast<std::remove_const_t<T>*>(data), byteSize()}; }
+
+ // Truncates `this` to a length of `offset` and returns a span with the
+ // remainder.
+ //
+ // Aborts if offset > size.
+ Span<T> splitOff(size_t offset) {
+ LOG_ALWAYS_FATAL_IF(offset > size);
+ Span<T> rest = {data + offset, size - offset};
+ size = offset;
+ return rest;
+ }
+};
+
} // namespace android
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index f295417..e864f9e 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -72,9 +72,9 @@
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
+ typedef INTERFACE BaseInterface;
protected:
- typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
@@ -85,9 +85,9 @@
{
public:
explicit BpInterface(const sp<IBinder>& remote);
+ typedef INTERFACE BaseInterface;
protected:
- typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index bb55831..413c97f 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -134,6 +134,12 @@
virtual status_t unregisterForNotifications(const String16& name,
const sp<LocalRegistrationCallback>& callback) = 0;
+
+ struct ServiceDebugInfo {
+ std::string name;
+ int pid;
+ };
+ virtual std::vector<ServiceDebugInfo> getServiceDebugInfo() = 0;
};
sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 6b31812..dba8dd6 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -125,9 +125,17 @@
*/
void setRootObjectWeak(const wp<IBinder>& binder);
/**
- * Allows a root object to be created for each session
+ * Allows a root object to be created for each session.
+ *
+ * Takes one argument: a callable that is invoked once per new session.
+ * The callable takes two arguments: a type-erased pointer to an OS- and
+ * transport-specific address structure, e.g., sockaddr_vm for vsock, and
+ * an integer representing the size in bytes of that structure. The
+ * callable should validate the size, then cast the type-erased pointer
+ * to a pointer to the actual type of the address, e.g., const void* to
+ * const sockaddr_vm*.
*/
- void setPerSessionRootObject(std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& object);
+ void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object);
sp<IBinder> getRootObject();
/**
@@ -177,8 +185,9 @@
void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
+ static constexpr size_t kRpcAddressSize = 128;
static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
- const sockaddr_storage addr, socklen_t addrLen);
+ std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen);
[[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
const std::unique_ptr<RpcTransportCtx> mCtx;
@@ -192,7 +201,7 @@
std::map<std::thread::id, std::thread> mConnectingThreads;
sp<IBinder> mRootObject;
wp<IBinder> mRootObjectWeak;
- std::function<sp<IBinder>(const sockaddr*, socklen_t)> mRootObjectFactory;
+ std::function<sp<IBinder>(const void*, size_t)> mRootObjectFactory;
std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
std::unique_ptr<FdTrigger> mShutdownTrigger;
std::condition_variable mShutdownCv;
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index cb81584..7d5d481 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -38,7 +38,13 @@
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 1;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
-constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = 0;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;
+
+// Starting with this version:
+//
+// * RpcWireReply is larger (4 bytes -> 20).
+// * RpcWireTransaction and RpcWireReplyV1 include the parcel data size.
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE = 1;
/**
* This represents a session (group of connections) between a client
@@ -258,6 +264,7 @@
sp<RpcConnection> assignIncomingConnectionToThisThread(
std::unique_ptr<RpcTransport> rpcTransport);
[[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
+ void clearConnectionTid(const sp<RpcConnection>& connection);
[[nodiscard]] status_t initShutdownTrigger();
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index bf2b25b..a3d42b7 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -38,10 +38,10 @@
<< " error: " << statusToString(status).c_str();
return false;
}
- server->setPerSessionRootObject([=](const sockaddr* addr, socklen_t addrlen) {
- LOG_ALWAYS_FATAL_IF(addr->sa_family != AF_VSOCK, "address is not a vsock");
+ server->setPerSessionRootObject([=](const void* addr, size_t addrlen) {
LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
+ LOG_ALWAYS_FATAL_IF(vaddr->svm_family != AF_VSOCK, "address is not a vsock");
return AIBinder_toPlatformBinder(factory(vaddr->svm_cid, factoryContext));
});
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 79c8c8f..32e018d 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -113,6 +113,7 @@
"abseil-*",
"android-*",
"bugprone-*",
+ "-bugprone-branch-clone", // b/155034972
"cert-*",
"clang-analyzer-*",
"-clang-analyzer-core.CallAndMessage",
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 28e3ff4..b21a7e9 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -36,6 +36,7 @@
using ::android::Parcel;
using ::android::sp;
using ::android::status_t;
+using ::android::statusToString;
using ::android::String16;
using ::android::String8;
using ::android::wp;
@@ -133,7 +134,8 @@
} else {
// b/155793159
LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
- << "' to dead binder.";
+ << "' to dead binder with cached descriptor '" << SanitizeString(descriptor)
+ << "'.";
}
return false;
}
@@ -458,7 +460,8 @@
status_t status = binder->unlinkToDeath(recipient, cookie, 0 /*flags*/);
if (status != ::android::OK) {
LOG(ERROR) << __func__
- << ": removed reference to death recipient but unlink failed.";
+ << ": removed reference to death recipient but unlink failed: "
+ << statusToString(status);
}
return PruneStatusT(status);
}
@@ -539,7 +542,8 @@
binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) {
if (binder == nullptr || recipient == nullptr) {
- LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+ LOG(ERROR) << __func__ << ": Must provide binder (" << binder << ") and recipient ("
+ << recipient << ")";
return STATUS_UNEXPECTED_NULL;
}
@@ -550,7 +554,8 @@
binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) {
if (binder == nullptr || recipient == nullptr) {
- LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+ LOG(ERROR) << __func__ << ": Must provide binder (" << binder << ") and recipient ("
+ << recipient << ")";
return STATUS_UNEXPECTED_NULL;
}
@@ -625,7 +630,8 @@
binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
if (binder == nullptr || in == nullptr) {
- LOG(ERROR) << __func__ << ": requires non-null parameters.";
+ LOG(ERROR) << __func__ << ": requires non-null parameters binder (" << binder
+ << ") and in (" << in << ").";
return STATUS_UNEXPECTED_NULL;
}
const AIBinder_Class* clazz = binder->getClass();
@@ -671,7 +677,9 @@
AutoParcelDestroyer forIn(in, DestroyParcel);
if (!isUserCommand(code)) {
- LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK.";
+ LOG(ERROR) << __func__
+ << ": Only user-defined transactions can be made from the NDK, but requested: "
+ << code;
return STATUS_UNKNOWN_TRANSACTION;
}
@@ -682,7 +690,8 @@
}
if (binder == nullptr || *in == nullptr || out == nullptr) {
- LOG(ERROR) << __func__ << ": requires non-null parameters.";
+ LOG(ERROR) << __func__ << ": requires non-null parameters binder (" << binder << "), in ("
+ << in << "), and out (" << out << ").";
return STATUS_UNEXPECTED_NULL;
}
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index b7c7ae4..3edeebf 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -335,11 +335,16 @@
// We don't own this file, so we need to be careful not to drop it.
let file = ManuallyDrop::new(File::from_raw_fd(fd));
- if args.is_null() {
+ if args.is_null() && num_args != 0 {
return StatusCode::UNEXPECTED_NULL as status_t;
}
- let args = slice::from_raw_parts(args, num_args as usize);
- let args: Vec<_> = args.iter().map(|s| CStr::from_ptr(*s)).collect();
+
+ let args = if args.is_null() || num_args == 0 {
+ vec![]
+ } else {
+ slice::from_raw_parts(args, num_args as usize)
+ .iter().map(|s| CStr::from_ptr(*s)).collect()
+ };
let object = sys::AIBinder_getUserData(binder);
let binder: &T = &*(object as *const T);
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index fdd02a4..2deea82 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -24,6 +24,9 @@
// number of known RPC binders to process, RpcState::countBinders by session
int[] countBinders();
+ // Return a null binder with a non-nullable return type.
+ IBinder getNullBinder();
+
// Caller sends server, callee pings caller's server and returns error code.
int pingMe(IBinder binder);
@nullable IBinder repeatBinder(@nullable IBinder binder);
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index dd1a8c3..60b3c94 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -203,13 +203,15 @@
auto remoteBinder = session->getRootObject();
size_t mallocs = 0, totalBytes = 0;
- const auto on_malloc = OnMalloc([&](size_t bytes) {
- mallocs++;
- totalBytes += bytes;
- });
- CHECK_EQ(OK, remoteBinder->pingBinder());
- EXPECT_EQ(mallocs, 3);
- EXPECT_EQ(totalBytes, 60);
+ {
+ const auto on_malloc = OnMalloc([&](size_t bytes) {
+ mallocs++;
+ totalBytes += bytes;
+ });
+ CHECK_EQ(OK, remoteBinder->pingBinder());
+ }
+ EXPECT_EQ(mallocs, 1);
+ EXPECT_EQ(totalBytes, 40);
}
int main(int argc, char** argv) {
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 3e90726..4ed3309 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -30,6 +30,7 @@
#include <android-base/properties.h>
#include <android-base/result-gmock.h>
#include <android-base/result.h>
+#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <binder/Binder.h>
@@ -1232,6 +1233,53 @@
EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
}
+struct TooManyFdsFlattenable : Flattenable<TooManyFdsFlattenable> {
+ TooManyFdsFlattenable(size_t fdCount) : mFdCount(fdCount) {}
+
+ // Flattenable protocol
+ size_t getFlattenedSize() const {
+ // Return a valid non-zero size here so we don't get an unintended
+ // BAD_VALUE from Parcel::write
+ return 16;
+ }
+ size_t getFdCount() const { return mFdCount; }
+ status_t flatten(void *& /*buffer*/, size_t & /*size*/, int *&fds, size_t &count) const {
+ for (size_t i = 0; i < count; i++) {
+ fds[i] = STDIN_FILENO;
+ }
+ return NO_ERROR;
+ }
+ status_t unflatten(void const *& /*buffer*/, size_t & /*size*/, int const *& /*fds*/,
+ size_t & /*count*/) {
+ /* This doesn't get called */
+ return NO_ERROR;
+ }
+
+ size_t mFdCount;
+};
+
+TEST_F(BinderLibTest, TooManyFdsFlattenable) {
+ rlimit origNofile;
+ int ret = getrlimit(RLIMIT_NOFILE, &origNofile);
+ ASSERT_EQ(0, ret);
+
+ // Restore the original file limits when the test finishes
+ base::ScopeGuard guardUnguard([&]() { setrlimit(RLIMIT_NOFILE, &origNofile); });
+
+ rlimit testNofile = {1024, 1024};
+ ret = setrlimit(RLIMIT_NOFILE, &testNofile);
+ ASSERT_EQ(0, ret);
+
+ Parcel parcel;
+ // Try to write more file descriptors than supported by the OS
+ TooManyFdsFlattenable tooManyFds1(1024);
+ EXPECT_THAT(parcel.write(tooManyFds1), StatusEq(-EMFILE));
+
+ // Try to write more file descriptors than the internal limit
+ TooManyFdsFlattenable tooManyFds2(1025);
+ EXPECT_THAT(parcel.write(tooManyFds2), StatusEq(BAD_VALUE));
+}
+
TEST(ServiceNotifications, Unregister) {
auto sm = defaultServiceManager();
using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback;
@@ -1264,7 +1312,9 @@
std::vector<std::thread> ts;
for (size_t i = 0; i < kKernelThreads - 1; i++) {
ts.push_back(std::thread([&] {
- EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &reply), NO_ERROR);
+ Parcel local_reply;
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
+ NO_ERROR);
}));
}
@@ -1302,7 +1352,9 @@
size_t epochMsBefore = epochMillis();
for (size_t i = 0; i < kKernelThreads + 1; i++) {
ts.push_back(std::thread([&] {
- EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &reply), NO_ERROR);
+ Parcel local_reply;
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
+ NO_ERROR);
}));
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 4161a7a..141fa38 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -99,17 +99,19 @@
EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
}
-class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
+class BinderRpcServerOnly : public ::testing::TestWithParam<std::tuple<RpcSecurity, uint32_t>> {
public:
static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
- return newFactory(info.param)->toCString();
+ return std::string(newFactory(std::get<0>(info.param))->toCString()) + "_serverV" +
+ std::to_string(std::get<1>(info.param));
}
};
-TEST_P(BinderRpcSimple, SetExternalServerTest) {
+TEST_P(BinderRpcServerOnly, SetExternalServerTest) {
base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
int sinkFd = sink.get();
- auto server = RpcServer::make(newFactory(GetParam()));
+ auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
+ server->setProtocolVersion(std::get<1>(GetParam()));
ASSERT_FALSE(server->hasServer());
ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
ASSERT_TRUE(server->hasServer());
@@ -200,6 +202,10 @@
}
return Status::ok();
}
+ Status getNullBinder(sp<IBinder>* out) override {
+ out->clear();
+ return Status::ok();
+ }
Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
if (binder == nullptr) {
std::cout << "Received null binder!" << std::endl;
@@ -480,7 +486,8 @@
return serverFd;
}
-class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
+class BinderRpc
+ : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t>> {
public:
struct Options {
size_t numThreads = 1;
@@ -490,8 +497,9 @@
};
static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
- auto [type, security] = info.param;
- return PrintToString(type) + "_" + newFactory(security)->toCString();
+ auto [type, security, clientVersion, serverVersion] = info.param;
+ return PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
+ std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
}
static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
@@ -533,16 +541,19 @@
SocketType socketType = std::get<0>(GetParam());
RpcSecurity rpcSecurity = std::get<1>(GetParam());
+ uint32_t clientVersion = std::get<2>(GetParam());
+ uint32_t serverVersion = std::get<3>(GetParam());
unsigned int vsockPort = allocateVsockPort();
std::string addr = allocateSocketAddress();
auto ret = ProcessSession{
- .host = Process([&](android::base::borrowed_fd writeEnd,
+ .host = Process([=](android::base::borrowed_fd writeEnd,
android::base::borrowed_fd readEnd) {
auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
+ server->setProtocolVersion(serverVersion);
server->setMaxThreads(options.numThreads);
unsigned int outPort = 0;
@@ -618,6 +629,7 @@
status_t status;
for (const auto& session : sessions) {
+ CHECK(session->setProtocolVersion(clientVersion));
session->setMaxIncomingThreads(options.numIncomingConnections);
session->setMaxOutgoingThreads(options.numOutgoingConnections);
@@ -650,8 +662,11 @@
.proc = createRpcTestSocketServerProcess(
options,
[&](const sp<RpcServer>& server) {
- server->setPerSessionRootObject([&](const sockaddr* addr,
- socklen_t len) {
+ server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
+ // UNIX sockets with abstract addresses return
+ // sizeof(sa_family_t)==2 in addrlen
+ CHECK_GE(len, sizeof(sa_family_t));
+ const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
switch (addr->sa_family) {
case AF_UNIX:
@@ -752,7 +767,7 @@
p1.markForBinder(proc1.rootBinder);
p1.writeInt32(3);
- EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, p1.dataSize()));
+ EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
Parcel p2;
@@ -791,6 +806,13 @@
EXPECT_EQ(single + single, doubled);
}
+TEST_P(BinderRpc, InvalidNullBinderReturn) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(proc.rootIface->getNullBinder(&outBinder).transactionError(), UNEXPECTED_NULL);
+}
+
TEST_P(BinderRpc, CallMeBack) {
auto proc = createRpcTestSocketServerProcess({});
@@ -1417,9 +1439,20 @@
return ret;
}
+static std::vector<uint32_t> testVersions() {
+ std::vector<uint32_t> versions;
+ for (size_t i = 0; i < RPC_WIRE_PROTOCOL_VERSION_NEXT; i++) {
+ versions.push_back(i);
+ }
+ versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+ return versions;
+}
+
INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
::testing::Combine(::testing::ValuesIn(testSocketTypes()),
- ::testing::ValuesIn(RpcSecurityValues())),
+ ::testing::ValuesIn(RpcSecurityValues()),
+ ::testing::ValuesIn(testVersions()),
+ ::testing::ValuesIn(testVersions())),
BinderRpc::PrintParamInfo);
class BinderRpcServerRootObject
@@ -1473,9 +1506,10 @@
bool mValue = false;
};
-TEST_P(BinderRpcSimple, Shutdown) {
+TEST_P(BinderRpcServerOnly, Shutdown) {
auto addr = allocateSocketAddress();
- auto server = RpcServer::make(newFactory(GetParam()));
+ auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
+ server->setProtocolVersion(std::get<1>(GetParam()));
ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
auto joinEnds = std::make_shared<OneOffSignal>();
@@ -1545,12 +1579,17 @@
ASSERT_EQ(OK, rpcBinder->pingBinder());
}
-INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
- BinderRpcSimple::PrintTestParam);
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerOnly,
+ ::testing::Combine(::testing::ValuesIn(RpcSecurityValues()),
+ ::testing::ValuesIn(testVersions())),
+ BinderRpcServerOnly::PrintTestParam);
class RpcTransportTestUtils {
public:
- using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>;
+ // Only parameterized only server version because `RpcSession` is bypassed
+ // in the client half of the tests.
+ using Param =
+ std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>, uint32_t>;
using ConnectToServer = std::function<base::unique_fd()>;
// A server that handles client socket connections.
@@ -1562,8 +1601,9 @@
[[nodiscard]] AssertionResult setUp(
const Param& param,
std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
- auto [socketType, rpcSecurity, certificateFormat] = param;
+ auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
+ rpcServer->setProtocolVersion(serverVersion);
switch (socketType) {
case SocketType::PRECONNECTED: {
return AssertionFailure() << "Not supported by this test";
@@ -1693,7 +1733,8 @@
explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
Client(Client&&) = default;
[[nodiscard]] AssertionResult setUp(const Param& param) {
- auto [socketType, rpcSecurity, certificateFormat] = param;
+ auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
+ (void)serverVersion;
mFdTrigger = FdTrigger::make();
mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
@@ -1764,23 +1805,28 @@
using Server = RpcTransportTestUtils::Server;
using Client = RpcTransportTestUtils::Client;
static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
- auto [socketType, rpcSecurity, certificateFormat] = info.param;
+ auto [socketType, rpcSecurity, certificateFormat, serverVersion] = info.param;
auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
+ ret += "_serverV" + std::to_string(serverVersion);
return ret;
}
static std::vector<ParamType> getRpcTranportTestParams() {
std::vector<ParamType> ret;
- for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
- for (auto rpcSecurity : RpcSecurityValues()) {
- switch (rpcSecurity) {
- case RpcSecurity::RAW: {
- ret.emplace_back(socketType, rpcSecurity, std::nullopt);
- } break;
- case RpcSecurity::TLS: {
- ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
- ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
- } break;
+ for (auto serverVersion : testVersions()) {
+ for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
+ for (auto rpcSecurity : RpcSecurityValues()) {
+ switch (rpcSecurity) {
+ case RpcSecurity::RAW: {
+ ret.emplace_back(socketType, rpcSecurity, std::nullopt, serverVersion);
+ } break;
+ case RpcSecurity::TLS: {
+ ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM,
+ serverVersion);
+ ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER,
+ serverVersion);
+ } break;
+ }
}
}
}
@@ -1788,7 +1834,8 @@
}
template <typename A, typename B>
status_t trust(const A& a, const B& b) {
- auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+ (void)serverVersion;
return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
}
};
@@ -1824,7 +1871,8 @@
}
TEST_P(RpcTransportTest, UntrustedServer) {
- auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+ (void)serverVersion;
auto untrustedServer = std::make_unique<Server>();
ASSERT_TRUE(untrustedServer->setUp(GetParam()));
@@ -1842,7 +1890,9 @@
client.run(handshakeOk);
}
TEST_P(RpcTransportTest, MaliciousServer) {
- auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+ (void)serverVersion;
+
auto validServer = std::make_unique<Server>();
ASSERT_TRUE(validServer->setUp(GetParam()));
@@ -1865,7 +1915,9 @@
}
TEST_P(RpcTransportTest, UntrustedClient) {
- auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+ (void)serverVersion;
+
auto server = std::make_unique<Server>();
ASSERT_TRUE(server->setUp(GetParam()));
@@ -1884,7 +1936,9 @@
}
TEST_P(RpcTransportTest, MaliciousClient) {
- auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+ (void)serverVersion;
+
auto server = std::make_unique<Server>();
ASSERT_TRUE(server->setUp(GetParam()));
@@ -1970,23 +2024,24 @@
RpcTransportTest::PrintParamInfo);
class RpcTransportTlsKeyTest
- : public testing::TestWithParam<std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat>> {
+ : public testing::TestWithParam<
+ std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat, uint32_t>> {
public:
template <typename A, typename B>
status_t trust(const A& a, const B& b) {
- auto [socketType, certificateFormat, keyFormat] = GetParam();
+ auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
+ (void)serverVersion;
return RpcTransportTestUtils::trust(RpcSecurity::TLS, certificateFormat, a, b);
}
static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
- auto [socketType, certificateFormat, keyFormat] = info.param;
- auto ret = PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
- "_key_" + PrintToString(keyFormat);
- return ret;
+ auto [socketType, certificateFormat, keyFormat, serverVersion] = info.param;
+ return PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
+ "_key_" + PrintToString(keyFormat) + "_serverV" + std::to_string(serverVersion);
};
};
TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
- auto [socketType, certificateFormat, keyFormat] = GetParam();
+ auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
std::vector<uint8_t> pkeyData, certData;
{
@@ -2001,8 +2056,8 @@
auto desPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
auto desCert = deserializeCertificate(certData, certificateFormat);
auto auth = std::make_unique<RpcAuthPreSigned>(std::move(desPkey), std::move(desCert));
- auto utilsParam =
- std::make_tuple(socketType, RpcSecurity::TLS, std::make_optional(certificateFormat));
+ auto utilsParam = std::make_tuple(socketType, RpcSecurity::TLS,
+ std::make_optional(certificateFormat), serverVersion);
auto server = std::make_unique<RpcTransportTestUtils::Server>();
ASSERT_TRUE(server->setUp(utilsParam, std::move(auth)));
@@ -2021,7 +2076,8 @@
BinderRpc, RpcTransportTlsKeyTest,
testing::Combine(testing::ValuesIn(testSocketTypes(false /* hasPreconnected*/)),
testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
- testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER)),
+ testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+ testing::ValuesIn(testVersions())),
RpcTransportTlsKeyTest::PrintParamInfo);
} // namespace android
diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
index 4fcf42d..3dab2c7 100644
--- a/libs/binder/tests/binderRpcWireProtocolTest.cpp
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -233,11 +233,15 @@
"0100000025000000|03000000|00000000|ffffffff|03000000|00000000|00000000|"
"07000000020000003a0044000000000000000000|f8ffffff020000003a002f00000000000000000008000000";
+TEST(RpcWire, V0) {
+ checkRepr(kCurrentRepr, 0);
+}
+
TEST(RpcWire, CurrentVersion) {
checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
}
-static_assert(RPC_WIRE_PROTOCOL_VERSION == 0,
+static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
"If the binder wire protocol is updated, this test should test additional versions. "
"The binder wire protocol should only be updated on upstream AOSP.");
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
index acda402..09fbdea 100644
--- a/libs/dumputils/Android.bp
+++ b/libs/dumputils/Android.bp
@@ -26,6 +26,7 @@
shared_libs: [
"libbase",
+ "libbinder",
"libhidlbase",
"liblog",
"libutils",
@@ -33,7 +34,10 @@
srcs: ["dump_utils.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
export_include_dirs: [
"include",
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 29c788b..0f1a02a 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -20,6 +20,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <dumputils/dump_utils.h>
#include <log/log.h>
@@ -52,8 +53,8 @@
NULL,
};
-/* list of hal interface to dump containing process during native dumps */
-static const char* hal_interfaces_to_dump[] {
+/* list of hidl hal interface to dump containing process during native dumps */
+static const char* hidl_hal_interfaces_to_dump[] {
"android.hardware.audio@4.0::IDevicesFactory",
"android.hardware.audio@5.0::IDevicesFactory",
"android.hardware.audio@6.0::IDevicesFactory",
@@ -82,6 +83,11 @@
NULL,
};
+/* list of hal interface to dump containing process during native dumps */
+static const std::vector<std::string> aidl_interfaces_to_dump {
+ "android.hardware.camera.provider.ICameraProvider",
+};
+
/* list of extra hal interfaces to dump containing process during native dumps */
// This is filled when dumpstate is called.
static std::set<const std::string> extra_hal_interfaces_to_dump;
@@ -104,7 +110,7 @@
// check if interface is included in either default hal list or extra hal list
bool should_dump_hal_interface(const std::string& interface) {
- for (const char** i = hal_interfaces_to_dump; *i; i++) {
+ for (const char** i = hidl_hal_interfaces_to_dump; *i; i++) {
if (interface == *i) {
return true;
}
@@ -130,14 +136,26 @@
return false;
}
-std::set<int> get_interesting_hal_pids() {
+static void get_interesting_aidl_pids(std::set<int> &pids) {
+ using ServiceDebugInfo = android::IServiceManager::ServiceDebugInfo;
+ auto sm = android::defaultServiceManager();
+ std::vector<ServiceDebugInfo> serviceDebugInfos = sm->getServiceDebugInfo();
+ for (const auto & serviceDebugInfo : serviceDebugInfos) {
+ for (const auto &aidl_prefix : aidl_interfaces_to_dump) {
+ // Check for prefix match with aidl interface to dump
+ if (serviceDebugInfo.name.rfind(aidl_prefix, 0) == 0) {
+ pids.insert(serviceDebugInfo.pid);
+ }
+ }
+ }
+}
+
+static void get_interesting_hidl_pids(std::set<int> &pids) {
using android::hidl::manager::V1_0::IServiceManager;
using android::sp;
using android::hardware::Return;
sp<IServiceManager> manager = IServiceManager::getService();
- std::set<int> pids;
-
read_extra_hals_to_dump_from_property();
Return<void> ret = manager->debugDump([&](auto& hals) {
@@ -146,11 +164,9 @@
continue;
}
- if (!should_dump_hal_interface(info.interfaceName)) {
- continue;
+ if (should_dump_hal_interface(info.interfaceName)) {
+ pids.insert(info.pid);
}
-
- pids.insert(info.pid);
}
});
@@ -158,7 +174,14 @@
ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
}
- return pids; // whether it was okay or not
+ return;
+}
+
+std::set<int> get_interesting_pids() {
+ std::set<int> interesting_pids;
+ get_interesting_hidl_pids(interesting_pids);
+ get_interesting_aidl_pids(interesting_pids);
+ return interesting_pids;
}
bool IsZygote(int pid) {
diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h
index 25f7127..7c5329d 100644
--- a/libs/dumputils/include/dumputils/dump_utils.h
+++ b/libs/dumputils/include/dumputils/dump_utils.h
@@ -21,7 +21,7 @@
bool should_dump_native_traces(const char* path);
-std::set<int> get_interesting_hal_pids();
+std::set<int> get_interesting_pids();
bool IsZygote(int pid);
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 61e4a98..6c6d7f3 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -94,4 +94,8 @@
return INVALID_OPERATION;
}
+std::vector<IServiceManager::ServiceDebugInfo> ServiceManager::getServiceDebugInfo() {
+ std::vector<IServiceManager::ServiceDebugInfo> ret;
+ return ret;
+}
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 6d6e008..e0af5d4 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -20,6 +20,7 @@
#include <map>
#include <optional>
+#include <vector>
namespace android {
@@ -58,6 +59,9 @@
status_t unregisterForNotifications(const String16& name,
const sp<LocalRegistrationCallback>& callback) override;
+
+ std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
+
private:
std::map<String16, sp<IBinder>> mNameToService;
};
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 77a883b..bf275a5 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -391,6 +391,71 @@
}
}
+void layer_state_t::sanitize(int32_t permissions) {
+ // TODO: b/109894387
+ //
+ // SurfaceFlinger's renderer is not prepared to handle cropping in the face of arbitrary
+ // rotation. To see the problem observe that if we have a square parent, and a child
+ // of the same size, then we rotate the child 45 degrees around its center, the child
+ // must now be cropped to a non rectangular 8 sided region.
+ //
+ // Of course we can fix this in the future. For now, we are lucky, SurfaceControl is
+ // private API, and arbitrary rotation is used in limited use cases, for instance:
+ // - WindowManager only uses rotation in one case, which is on a top level layer in which
+ // cropping is not an issue.
+ // - Launcher, as a privileged app, uses this to transition an application to PiP
+ // (picture-in-picture) mode.
+ //
+ // However given that abuse of rotation matrices could lead to surfaces extending outside
+ // of cropped areas, we need to prevent non-root clients without permission
+ // ACCESS_SURFACE_FLINGER nor ROTATE_SURFACE_FLINGER
+ // (a.k.a. everyone except WindowManager / tests / Launcher) from setting non rectangle
+ // preserving transformations.
+ if (what & eMatrixChanged) {
+ if (!(permissions & Permission::ROTATE_SURFACE_FLINGER)) {
+ ui::Transform t;
+ t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+ if (!t.preserveRects()) {
+ what &= ~eMatrixChanged;
+ ALOGE("Stripped non rect preserving matrix in sanitize");
+ }
+ }
+ }
+
+ if (what & layer_state_t::eInputInfoChanged) {
+ if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+ what &= ~eInputInfoChanged;
+ ALOGE("Stripped attempt to set eInputInfoChanged in sanitize");
+ }
+ }
+ if (what & layer_state_t::eTrustedOverlayChanged) {
+ if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+ what &= ~eTrustedOverlayChanged;
+ ALOGE("Stripped attempt to set eTrustedOverlay in sanitize");
+ }
+ }
+ if (what & layer_state_t::eDropInputModeChanged) {
+ if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+ what &= ~eDropInputModeChanged;
+ ALOGE("Stripped attempt to set eDropInputModeChanged in sanitize");
+ }
+ }
+ if (what & layer_state_t::eFrameRateSelectionPriority) {
+ if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+ what &= ~eFrameRateSelectionPriority;
+ ALOGE("Stripped attempt to set eFrameRateSelectionPriority in sanitize");
+ }
+ }
+ if (what & layer_state_t::eFrameRateChanged) {
+ if (!ValidateFrameRate(frameRate, frameRateCompatibility,
+ changeFrameRateStrategy,
+ "layer_state_t::sanitize",
+ permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+ what &= ~eFrameRateChanged; // logged in ValidateFrameRate
+ }
+ }
+}
+
void layer_state_t::merge(const layer_state_t& other) {
if (other.what & ePositionChanged) {
what |= ePositionChanged;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 725ea65..4bcc9d5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -551,6 +551,13 @@
mListenerCallbacks = other.mListenerCallbacks;
}
+void SurfaceComposerClient::Transaction::sanitize() {
+ for (auto & [handle, composerState] : mComposerStates) {
+ composerState.state.sanitize(0 /* permissionMask */);
+ }
+ mInputWindowCommands.clear();
+}
+
std::unique_ptr<SurfaceComposerClient::Transaction>
SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) {
auto transaction = std::make_unique<Transaction>();
@@ -635,7 +642,6 @@
if (composerState.read(*parcel) == BAD_VALUE) {
return BAD_VALUE;
}
-
composerStates[surfaceControlHandle] = composerState;
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 03e4aac..2a8d30d 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -61,6 +61,12 @@
* Used to communicate layer information between SurfaceFlinger and its clients.
*/
struct layer_state_t {
+ enum Permission {
+ ACCESS_SURFACE_FLINGER = 0x1,
+ ROTATE_SURFACE_FLINGER = 0x2,
+ INTERNAL_SYSTEM_WINDOW = 0x4,
+ };
+
enum {
eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java
eLayerOpaque = 0x02, // SURFACE_OPAQUE
@@ -128,6 +134,7 @@
status_t read(const Parcel& input);
bool hasBufferChanges() const;
bool hasValidBuffer() const;
+ void sanitize(int32_t permissions);
struct matrix22_t {
float dsdx{0};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0d1d1a3..76b6d44 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -590,6 +590,14 @@
void setAnimationTransaction();
void setEarlyWakeupStart();
void setEarlyWakeupEnd();
+
+ /**
+ * Strip the transaction of all permissioned requests, required when
+ * accepting transactions across process boundaries.
+ *
+ * TODO (b/213644870): Remove all permissioned things from Transaction
+ */
+ void sanitize();
};
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index eb0d821..cdcdaab 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -62,6 +62,7 @@
"libbase",
"liblog",
"libcutils",
+ "libvintf",
],
static_libs: [
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 1aec477..18cd474 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -53,33 +53,39 @@
}
std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
- const InputDeviceIdentifier& deviceIdentifier,
- InputDeviceConfigurationFileType type) {
+ const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type,
+ const char* suffix) {
if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
if (deviceIdentifier.version != 0) {
// Try vendor product version.
- std::string versionPath = getInputDeviceConfigurationFilePathByName(
- StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
- deviceIdentifier.vendor, deviceIdentifier.product,
- deviceIdentifier.version),
- type);
+ std::string versionPath =
+ getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%"
+ "04x_Version_%04x%s",
+ deviceIdentifier.vendor,
+ deviceIdentifier.product,
+ deviceIdentifier.version,
+ suffix),
+ type);
if (!versionPath.empty()) {
return versionPath;
}
}
// Try vendor product.
- std::string productPath = getInputDeviceConfigurationFilePathByName(
- StringPrintf("Vendor_%04x_Product_%04x",
- deviceIdentifier.vendor, deviceIdentifier.product),
- type);
+ std::string productPath =
+ getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%04x%s",
+ deviceIdentifier.vendor,
+ deviceIdentifier.product,
+ suffix),
+ type);
if (!productPath.empty()) {
return productPath;
}
}
// Try device name.
- return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
+ return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName() + suffix,
+ type);
}
std::string getInputDeviceConfigurationFilePathByName(
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index c365ab0..84a8ab4 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -23,20 +23,33 @@
#include <input/InputEventLabels.h>
#include <input/KeyLayoutMap.h>
#include <input/Keyboard.h>
+#include <log/log.h>
#include <utils/Errors.h>
-#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/Tokenizer.h>
+#include <vintf/RuntimeInfo.h>
+#include <vintf/VintfObject.h>
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
+#include <cstdlib>
+#include <string_view>
+#include <unordered_map>
+
+/**
+ * Log debug output for the parser.
+ * Enable this via "adb shell setprop log.tag.KeyLayoutMapParser DEBUG" (requires restart)
+ */
+const bool DEBUG_PARSER =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Parser", ANDROID_LOG_INFO);
// Enables debug output for parser performance.
#define DEBUG_PARSER_PERFORMANCE 0
-// Enables debug output for mapping.
-#define DEBUG_MAPPING 0
-
+/**
+ * Log debug output for mapping.
+ * Enable this via "adb shell setprop log.tag.KeyLayoutMapMapping DEBUG" (requires restart)
+ */
+const bool DEBUG_MAPPING =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Mapping", ANDROID_LOG_INFO);
namespace android {
@@ -62,6 +75,29 @@
{SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE_UNCALIBRATED)},
{SENSOR_ENTRY(InputDeviceSensorType::SIGNIFICANT_MOTION)}};
+bool kernelConfigsArePresent(const std::set<std::string>& configs) {
+ std::shared_ptr<const android::vintf::RuntimeInfo> runtimeInfo =
+ android::vintf::VintfObject::GetInstance()->getRuntimeInfo(
+ vintf::RuntimeInfo::FetchFlag::CONFIG_GZ);
+ LOG_ALWAYS_FATAL_IF(runtimeInfo == nullptr, "Kernel configs could not be fetched");
+
+ const std::map<std::string, std::string>& kernelConfigs = runtimeInfo->kernelConfigs();
+ for (const std::string& requiredConfig : configs) {
+ const auto configIt = kernelConfigs.find(requiredConfig);
+ if (configIt == kernelConfigs.end()) {
+ ALOGI("Required kernel config %s is not found", requiredConfig.c_str());
+ return false;
+ }
+ const std::string& option = configIt->second;
+ if (option != "y" && option != "m") {
+ ALOGI("Required kernel config %s has option %s", requiredConfig.c_str(),
+ option.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
// --- KeyLayoutMap ---
KeyLayoutMap::KeyLayoutMap() {
@@ -72,32 +108,34 @@
base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::loadContents(const std::string& filename,
const char* contents) {
- Tokenizer* tokenizer;
- status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
- if (status) {
- ALOGE("Error %d opening key layout map.", status);
- return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
- }
- std::unique_ptr<Tokenizer> t(tokenizer);
- auto ret = load(t.get());
- if (ret.ok()) {
- (*ret)->mLoadFileName = filename;
- }
- return ret;
+ return load(filename, contents);
}
-base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename) {
+base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename,
+ const char* contents) {
Tokenizer* tokenizer;
- status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
+ status_t status;
+ if (contents == nullptr) {
+ status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
+ } else {
+ status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
+ }
if (status) {
ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
}
std::unique_ptr<Tokenizer> t(tokenizer);
auto ret = load(t.get());
- if (ret.ok()) {
- (*ret)->mLoadFileName = filename;
+ if (!ret.ok()) {
+ return ret;
}
+ const std::shared_ptr<KeyLayoutMap>& map = *ret;
+ LOG_ALWAYS_FATAL_IF(map == nullptr, "Returned map should not be null if there's no error");
+ if (!kernelConfigsArePresent(map->mRequiredKernelConfigs)) {
+ ALOGI("Not loading %s because the required kernel configs are not set", filename.c_str());
+ return Errorf("Missing kernel config");
+ }
+ map->mLoadFileName = filename;
return ret;
}
@@ -130,9 +168,8 @@
int32_t* outKeyCode, uint32_t* outFlags) const {
const Key* key = getKey(scanCode, usageCode);
if (!key) {
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
-#endif
+ ALOGD_IF(DEBUG_MAPPING, "mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode,
+ usageCode);
*outKeyCode = AKEYCODE_UNKNOWN;
*outFlags = 0;
return NAME_NOT_FOUND;
@@ -141,10 +178,9 @@
*outKeyCode = key->keyCode;
*outFlags = key->flags;
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
- scanCode, usageCode, *outKeyCode, *outFlags);
-#endif
+ ALOGD_IF(DEBUG_MAPPING,
+ "mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
+ scanCode, usageCode, *outKeyCode, *outFlags);
return NO_ERROR;
}
@@ -152,103 +188,79 @@
base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(int32_t absCode) {
auto it = mSensorsByAbsCode.find(absCode);
if (it == mSensorsByAbsCode.end()) {
-#if DEBUG_MAPPING
- ALOGD("mapSensor: absCode=%d, ~ Failed.", absCode);
-#endif
+ ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode);
return Errorf("Can't find abs code {}.", absCode);
}
const Sensor& sensor = it->second;
-
-#if DEBUG_MAPPING
- ALOGD("mapSensor: absCode=%d, sensorType=0x%0x, sensorDataIndex=0x%x.", absCode,
- NamedEnum::string(sensor.sensorType), sensor.sensorDataIndex);
-#endif
+ ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
+ NamedEnum::string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
}
const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
if (usageCode) {
- ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
- if (index >= 0) {
- return &mKeysByUsageCode.valueAt(index);
+ auto it = mKeysByUsageCode.find(usageCode);
+ if (it != mKeysByUsageCode.end()) {
+ return &it->second;
}
}
if (scanCode) {
- ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
- if (index >= 0) {
- return &mKeysByScanCode.valueAt(index);
+ auto it = mKeysByScanCode.find(scanCode);
+ if (it != mKeysByScanCode.end()) {
+ return &it->second;
}
}
return nullptr;
}
-status_t KeyLayoutMap::findScanCodesForKey(
- int32_t keyCode, std::vector<int32_t>* outScanCodes) const {
- const size_t N = mKeysByScanCode.size();
- for (size_t i=0; i<N; i++) {
- if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
- outScanCodes->push_back(mKeysByScanCode.keyAt(i));
+std::vector<int32_t> KeyLayoutMap::findScanCodesForKey(int32_t keyCode) const {
+ std::vector<int32_t> scanCodes;
+ for (const auto& [scanCode, key] : mKeysByScanCode) {
+ if (keyCode == key.keyCode) {
+ scanCodes.push_back(scanCode);
}
}
- return NO_ERROR;
+ return scanCodes;
}
-status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
- ssize_t index = mAxes.indexOfKey(scanCode);
- if (index < 0) {
-#if DEBUG_MAPPING
- ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
-#endif
- return NAME_NOT_FOUND;
+std::optional<AxisInfo> KeyLayoutMap::mapAxis(int32_t scanCode) const {
+ auto it = mAxes.find(scanCode);
+ if (it == mAxes.end()) {
+ ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
+ return std::nullopt;
}
- *outAxisInfo = mAxes.valueAt(index);
-
-#if DEBUG_MAPPING
- ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
- "splitValue=%d, flatOverride=%d.",
- scanCode,
- outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
- outAxisInfo->splitValue, outAxisInfo->flatOverride);
-#endif
- return NO_ERROR;
+ const AxisInfo& axisInfo = it->second;
+ ALOGD_IF(DEBUG_MAPPING,
+ "mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
+ "splitValue=%d, flatOverride=%d.",
+ scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
+ axisInfo.flatOverride);
+ return axisInfo;
}
-status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const {
- const size_t N = mLedsByScanCode.size();
- for (size_t i = 0; i < N; i++) {
- if (mLedsByScanCode.valueAt(i).ledCode == ledCode) {
- *outScanCode = mLedsByScanCode.keyAt(i);
-#if DEBUG_MAPPING
- ALOGD("findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode, *outScanCode);
-#endif
- return NO_ERROR;
+std::optional<int32_t> KeyLayoutMap::findScanCodeForLed(int32_t ledCode) const {
+ for (const auto& [scanCode, led] : mLedsByScanCode) {
+ if (led.ledCode == ledCode) {
+ ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, scanCode=%d.", __func__, ledCode, scanCode);
+ return scanCode;
}
}
-#if DEBUG_MAPPING
- ALOGD("findScanCodeForLed: ledCode=%d ~ Not found.", ledCode);
-#endif
- return NAME_NOT_FOUND;
+ ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
+ return std::nullopt;
}
-status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const {
- const size_t N = mLedsByUsageCode.size();
- for (size_t i = 0; i < N; i++) {
- if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) {
- *outUsageCode = mLedsByUsageCode.keyAt(i);
-#if DEBUG_MAPPING
- ALOGD("findUsageForLed: ledCode=%d, usage=%x.", ledCode, *outUsageCode);
-#endif
- return NO_ERROR;
+std::optional<int32_t> KeyLayoutMap::findUsageCodeForLed(int32_t ledCode) const {
+ for (const auto& [usageCode, led] : mLedsByUsageCode) {
+ if (led.ledCode == ledCode) {
+ ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, usage=%x.", __func__, ledCode, usageCode);
+ return usageCode;
}
}
-#if DEBUG_MAPPING
- ALOGD("findUsageForLed: ledCode=%d ~ Not found.", ledCode);
-#endif
- return NAME_NOT_FOUND;
+ ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
+ return std::nullopt;
}
-
// --- KeyLayoutMap::Parser ---
KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
@@ -260,10 +272,8 @@
status_t KeyLayoutMap::Parser::parse() {
while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
-#endif
+ ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
mTokenizer->skipDelimiters(WHITESPACE);
@@ -285,6 +295,10 @@
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseSensor();
if (status) return status;
+ } else if (keywordToken == "requires_kernel_config") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ status_t status = parseRequiredKernelConfig();
+ if (status) return status;
} else {
ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
keywordToken.string());
@@ -321,8 +335,9 @@
mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
}
- KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
- if (map.indexOfKey(code) >= 0) {
+ std::unordered_map<int32_t, Key>& map =
+ mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
+ if (map.find(code) != map.end()) {
ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
@@ -357,14 +372,13 @@
flags |= flag;
}
-#if DEBUG_PARSER
- ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
- mapUsage ? "usage" : "scan code", code, keyCode, flags);
-#endif
+ ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
+ mapUsage ? "usage" : "scan code", code, keyCode, flags);
+
Key key;
key.keyCode = keyCode;
key.flags = flags;
- map.add(code, key);
+ map.insert({code, key});
return NO_ERROR;
}
@@ -377,7 +391,7 @@
scanCodeToken.string());
return BAD_VALUE;
}
- if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
+ if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) {
ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
scanCodeToken.string());
return BAD_VALUE;
@@ -458,14 +472,12 @@
}
}
-#if DEBUG_PARSER
- ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
- "splitValue=%d, flatOverride=%d.",
- scanCode,
- axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
- axisInfo.splitValue, axisInfo.flatOverride);
-#endif
- mMap->mAxes.add(scanCode, axisInfo);
+ ALOGD_IF(DEBUG_PARSER,
+ "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
+ "splitValue=%d, flatOverride=%d.",
+ scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
+ axisInfo.flatOverride);
+ mMap->mAxes.insert({scanCode, axisInfo});
return NO_ERROR;
}
@@ -485,8 +497,9 @@
return BAD_VALUE;
}
- KeyedVector<int32_t, Led>& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
- if (map.indexOfKey(code) >= 0) {
+ std::unordered_map<int32_t, Led>& map =
+ mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
+ if (map.find(code) != map.end()) {
ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
@@ -501,14 +514,12 @@
return BAD_VALUE;
}
-#if DEBUG_PARSER
- ALOGD("Parsed led %s: code=%d, ledCode=%d.",
- mapUsage ? "usage" : "scan code", code, ledCode);
-#endif
+ ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code",
+ code, ledCode);
Led led;
led.ledCode = ledCode;
- map.add(code, led);
+ map.insert({code, led});
return NO_ERROR;
}
@@ -580,10 +591,8 @@
}
int32_t sensorDataIndex = indexOpt.value();
-#if DEBUG_PARSER
- ALOGD("Parsed sensor: abs code=%d, sensorType=%d, sensorDataIndex=%d.", code,
- NamedEnum::string(sensorType).c_str(), sensorDataIndex);
-#endif
+ ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
+ NamedEnum::string(sensorType).c_str(), sensorDataIndex);
Sensor sensor;
sensor.sensorType = sensorType;
@@ -591,4 +600,23 @@
map.emplace(code, sensor);
return NO_ERROR;
}
+
+// Parse the name of a required kernel config.
+// The layout won't be used if the specified kernel config is not present
+// Examples:
+// requires_kernel_config CONFIG_HID_PLAYSTATION
+status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() {
+ String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+ std::string configName = codeToken.string();
+
+ const auto result = mMap->mRequiredKernelConfigs.emplace(configName);
+ if (!result.second) {
+ ALOGE("%s: Duplicate entry for required kernel config %s.",
+ mTokenizer->getLocation().string(), configName.c_str());
+ return BAD_VALUE;
+ }
+
+ ALOGD_IF(DEBUG_PARSER, "Parsed required kernel config: name=%s", configName.c_str());
+ return NO_ERROR;
+}
};
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index f0895b3..c3f5151 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -20,16 +20,23 @@
#include <unistd.h>
#include <limits.h>
-#include <input/Keyboard.h>
-#include <input/InputEventLabels.h>
-#include <input/KeyLayoutMap.h>
-#include <input/KeyCharacterMap.h>
#include <input/InputDevice.h>
+#include <input/InputEventLabels.h>
+#include <input/KeyCharacterMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/Keyboard.h>
+#include <log/log.h>
#include <utils/Errors.h>
-#include <utils/Log.h>
namespace android {
+static std::string getPath(const InputDeviceIdentifier& deviceIdentifier, const std::string& name,
+ InputDeviceConfigurationFileType type) {
+ return name.empty()
+ ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
+ : getInputDeviceConfigurationFilePathByName(name, type);
+}
+
// --- KeyMap ---
KeyMap::KeyMap() {
@@ -111,11 +118,25 @@
}
base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path);
+ if (ret.ok()) {
+ keyLayoutMap = *ret;
+ keyLayoutFile = path;
+ return OK;
+ }
+
+ // Try to load fallback layout if the regular layout could not be loaded due to missing
+ // kernel modules
+ std::string fallbackPath(
+ getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier,
+ InputDeviceConfigurationFileType::
+ KEY_LAYOUT,
+ "_fallback"));
+ ret = KeyLayoutMap::load(fallbackPath);
if (!ret.ok()) {
return ret.error().code();
}
keyLayoutMap = *ret;
- keyLayoutFile = path;
+ keyLayoutFile = fallbackPath;
return OK;
}
@@ -137,14 +158,6 @@
return OK;
}
-std::string KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
- const std::string& name, InputDeviceConfigurationFileType type) {
- return name.empty()
- ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
- : getInputDeviceConfigurationFilePathByName(name, type);
-}
-
-
// --- Global functions ---
bool isKeyboardSpecialFunction(const PropertyMap* config) {
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 6ffe851..d947cd9 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -36,8 +36,9 @@
"liblog",
"libui",
"libutils",
+ "libvintf",
],
- data: ["data/*.kcm"],
+ data: ["data/*"],
test_suites: ["device-tests"],
}
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index 61e88df..e872fa4 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -64,13 +64,11 @@
mKeyMap.keyCharacterMapFile = path;
}
- virtual void SetUp() override {
+ void SetUp() override {
loadKeyLayout("Generic");
loadKeyCharacterMap("Generic");
}
- virtual void TearDown() override {}
-
KeyMap mKeyMap;
};
@@ -132,4 +130,20 @@
ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
}
+TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) {
+ std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_fake_config.kl";
+ base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
+ ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath;
+ // We assert error message here because it's used by 'validatekeymaps' tool
+ ASSERT_EQ("Missing kernel config", ret.error().message());
+}
+
+TEST(InputDeviceKeyLayoutTest, LoadsWhenRequiredKernelConfigIsPresent) {
+ std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_real_config.kl";
+ base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
+ ASSERT_TRUE(ret.ok()) << "Cannot load KeyLayout at " << klPath;
+ const std::shared_ptr<KeyLayoutMap>& map = *ret;
+ ASSERT_NE(nullptr, map) << "Map should be valid because CONFIG_UHID should always be present";
+}
+
} // namespace android
diff --git a/libs/input/tests/data/kl_with_required_fake_config.kl b/libs/input/tests/data/kl_with_required_fake_config.kl
new file mode 100644
index 0000000..2d0a507
--- /dev/null
+++ b/libs/input/tests/data/kl_with_required_fake_config.kl
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This KL should not be loaded unless the below config is present in the kernel
+# This config will never exist, and therefore this KL should never be loaded
+requires_kernel_config CONFIG_HID_FAKEMODULE
+
+# An arbitrary mapping taken from another file
+key 0x130 BUTTON_X
\ No newline at end of file
diff --git a/libs/input/tests/data/kl_with_required_real_config.kl b/libs/input/tests/data/kl_with_required_real_config.kl
new file mode 100644
index 0000000..303b23e
--- /dev/null
+++ b/libs/input/tests/data/kl_with_required_real_config.kl
@@ -0,0 +1,21 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This KL should not be loaded unless the below config is present in the kernel
+# The CONFIG_UHID option has been required for a while, and therefore it's safe
+# to assume that this will always be loaded
+requires_kernel_config CONFIG_UHID
+
+# An arbitrary mapping taken from another file
+key 0x130 BUTTON_X
\ No newline at end of file
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index de36a7a..8363104 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -1448,7 +1448,11 @@
setError(EGL_BAD_SURFACE, EGL_FALSE);
}
int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0);
- return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ if (err != 0) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ } else if (!s->cnx->useAngle) {
+ return EGL_TRUE;
+ } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below
}
if (attribute == EGL_TIMESTAMPS_ANDROID) {
@@ -1458,7 +1462,11 @@
return EGL_TRUE;
}
int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0);
- return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ if (err != 0) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ } else if (!s->cnx->useAngle) {
+ return EGL_TRUE;
+ } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below
}
if (s->setSmpte2086Attribute(attribute, value)) {
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index e916221..36ae179 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "gpuservice_unittest"
#include <android-base/stringprintf.h>
+#define BPF_MAP_MAKE_VISIBLE_FOR_TESTING
#include <bpf/BpfMap.h>
#include <gmock/gmock.h>
#include <gpumem/GpuMem.h>
@@ -65,11 +66,11 @@
mTestableGpuMem = TestableGpuMem(mGpuMem.get());
mTestableGpuMem.setInitialized();
errno = 0;
- mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
- BPF_F_NO_PREALLOC);
+ mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH,
+ TEST_MAP_SIZE,
+ BPF_F_NO_PREALLOC));
EXPECT_EQ(0, errno);
- EXPECT_LE(0, mTestMap.getMap().get());
EXPECT_TRUE(mTestMap.isValid());
}
diff --git a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
index d76f039..5c04210 100644
--- a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "gpuservice_unittest"
+#define BPF_MAP_MAKE_VISIBLE_FOR_TESTING
#include <bpf/BpfMap.h>
#include <gpumem/GpuMem.h>
#include <gtest/gtest.h>
@@ -64,11 +65,11 @@
mTestableGpuMem = TestableGpuMem(mGpuMem.get());
errno = 0;
- mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
- BPF_F_NO_PREALLOC);
+ mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH,
+ TEST_MAP_SIZE,
+ BPF_F_NO_PREALLOC));
EXPECT_EQ(0, errno);
- EXPECT_LE(0, mTestMap.getMap().get());
EXPECT_TRUE(mTestMap.isValid());
}
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
index 0baf1f9..3c7644f 100644
--- a/services/gpuservice/tests/unittests/GpuStatsTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -25,6 +25,7 @@
#include <gtest/gtest.h>
#include <stats_pull_atom_callback.h>
#include <statslog.h>
+#include <utils/Looper.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -62,8 +63,9 @@
// clang-format on
class GpuStatsTest : public testing::Test {
+ sp<android::Looper> looper;
public:
- GpuStatsTest() {
+ GpuStatsTest() : looper(Looper::prepare(0 /* opts */)) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
@@ -73,6 +75,10 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ // performs all pending callbacks until all data has been consumed
+ // gives time to process binder transactions by thread pool
+ looper->pollAll(1000);
}
std::string inputCommand(InputCommand cmd);
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 166f358..26c33d2 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -449,8 +449,7 @@
return false;
}
- std::vector<int32_t> scanCodes;
- keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
+ std::vector<int32_t> scanCodes = keyMap.keyLayoutMap->findScanCodesForKey(keycode);
const size_t N = scanCodes.size();
for (size_t i = 0; i < N && i <= KEY_MAX; i++) {
int32_t sc = scanCodes[i];
@@ -545,10 +544,10 @@
return NAME_NOT_FOUND;
}
- int32_t scanCode;
- if (keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) {
- if (scanCode >= 0 && scanCode <= LED_MAX && ledBitmask.test(scanCode)) {
- *outScanCode = scanCode;
+ std::optional<int32_t> scanCode = keyMap.keyLayoutMap->findScanCodeForLed(led);
+ if (scanCode.has_value()) {
+ if (*scanCode >= 0 && *scanCode <= LED_MAX && ledBitmask.test(*scanCode)) {
+ *outScanCode = *scanCode;
return NO_ERROR;
}
}
@@ -862,8 +861,7 @@
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
- std::vector<int32_t> scanCodes;
- device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
+ std::vector<int32_t> scanCodes = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode);
if (scanCodes.size() != 0) {
if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
for (size_t i = 0; i < scanCodes.size(); i++) {
@@ -921,20 +919,16 @@
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->keyMap.haveKeyLayout()) {
- std::vector<int32_t> scanCodes;
for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
- scanCodes.clear();
+ std::vector<int32_t> scanCodes =
+ device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex]);
- status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex],
- &scanCodes);
- if (!err) {
- // check the possible scan codes identified by the layout map against the
- // map of codes actually emitted by the driver
- for (size_t sc = 0; sc < scanCodes.size(); sc++) {
- if (device->keyBitmask.test(scanCodes[sc])) {
- outFlags[codeIndex] = 1;
- break;
- }
+ // check the possible scan codes identified by the layout map against the
+ // map of codes actually emitted by the driver
+ for (size_t sc = 0; sc < scanCodes.size(); sc++) {
+ if (device->keyBitmask.test(scanCodes[sc])) {
+ outFlags[codeIndex] = 1;
+ break;
}
}
}
@@ -988,14 +982,15 @@
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device != nullptr && device->keyMap.haveKeyLayout()) {
- status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo);
- if (err == NO_ERROR) {
- return NO_ERROR;
- }
+ if (device == nullptr || !device->keyMap.haveKeyLayout()) {
+ return NAME_NOT_FOUND;
}
-
- return NAME_NOT_FOUND;
+ std::optional<AxisInfo> info = device->keyMap.keyLayoutMap->mapAxis(scanCode);
+ if (!info.has_value()) {
+ return NAME_NOT_FOUND;
+ }
+ *outAxisInfo = *info;
+ return NO_ERROR;
}
base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int32_t deviceId,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index da7ff71..f94917c 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1608,8 +1608,10 @@
void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
for (const sp<Layer>& child : mDrawingChildren) {
child->mDrawingParent = newParent;
+ const float parentShadowRadius =
+ newParent->canDrawShadows() ? 0.f : newParent->mEffectiveShadowRadius;
child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
- newParent->mEffectiveShadowRadius);
+ parentShadowRadius);
}
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 46a6cfb..e60625b 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -805,10 +805,6 @@
}
}
- // NOTE: Any new formats that are added must be coordinated across different
- // Android users. This includes the ANGLE team (a layered implementation of
- // OpenGL-ES).
-
VkResult result = VK_SUCCESS;
if (formats) {
uint32_t transfer_count = all_formats.size();
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 438e5dd..61e3859 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -840,56 +840,52 @@
template <typename Visitor>
inline bool Iterate(Visitor* visitor, VkJsonDevice* device) {
bool ret = true;
- switch (device->properties.apiVersion ^
- VK_VERSION_PATCH(device->properties.apiVersion)) {
- case VK_API_VERSION_1_2:
- FALLTHROUGH_INTENDED;
- case VK_API_VERSION_1_1:
- ret &=
- visitor->Visit("subgroupProperties", &device->subgroup_properties) &&
- visitor->Visit("pointClippingProperties",
- &device->point_clipping_properties) &&
- visitor->Visit("multiviewProperties",
- &device->multiview_properties) &&
- visitor->Visit("idProperties", &device->id_properties) &&
- visitor->Visit("maintenance3Properties",
- &device->maintenance3_properties) &&
- visitor->Visit("16bitStorageFeatures",
- &device->bit16_storage_features) &&
- visitor->Visit("multiviewFeatures", &device->multiview_features) &&
- visitor->Visit("variablePointerFeatures",
- &device->variable_pointer_features) &&
- visitor->Visit("protectedMemoryFeatures",
- &device->protected_memory_features) &&
- visitor->Visit("samplerYcbcrConversionFeatures",
- &device->sampler_ycbcr_conversion_features) &&
- visitor->Visit("shaderDrawParameterFeatures",
- &device->shader_draw_parameter_features) &&
- visitor->Visit("externalFenceProperties",
- &device->external_fence_properties) &&
- visitor->Visit("externalSemaphoreProperties",
- &device->external_semaphore_properties);
- FALLTHROUGH_INTENDED;
- case VK_API_VERSION_1_0:
- ret &= visitor->Visit("properties", &device->properties) &&
- visitor->Visit("features", &device->features) &&
- visitor->Visit("memory", &device->memory) &&
- visitor->Visit("queues", &device->queues) &&
- visitor->Visit("extensions", &device->extensions) &&
- visitor->Visit("layers", &device->layers) &&
- visitor->Visit("formats", &device->formats);
- if (device->ext_driver_properties.reported) {
- ret &= visitor->Visit("VK_KHR_driver_properties",
- &device->ext_driver_properties);
- }
- if (device->ext_variable_pointer_features.reported) {
- ret &= visitor->Visit("VK_KHR_variable_pointers",
- &device->ext_variable_pointer_features);
- }
- if (device->ext_shader_float16_int8_features.reported) {
- ret &= visitor->Visit("VK_KHR_shader_float16_int8",
- &device->ext_shader_float16_int8_features);
- }
+ if (device->properties.apiVersion >= VK_API_VERSION_1_1) {
+ ret &=
+ visitor->Visit("subgroupProperties", &device->subgroup_properties) &&
+ visitor->Visit("pointClippingProperties",
+ &device->point_clipping_properties) &&
+ visitor->Visit("multiviewProperties",
+ &device->multiview_properties) &&
+ visitor->Visit("idProperties", &device->id_properties) &&
+ visitor->Visit("maintenance3Properties",
+ &device->maintenance3_properties) &&
+ visitor->Visit("16bitStorageFeatures",
+ &device->bit16_storage_features) &&
+ visitor->Visit("multiviewFeatures", &device->multiview_features) &&
+ visitor->Visit("variablePointerFeatures",
+ &device->variable_pointer_features) &&
+ visitor->Visit("protectedMemoryFeatures",
+ &device->protected_memory_features) &&
+ visitor->Visit("samplerYcbcrConversionFeatures",
+ &device->sampler_ycbcr_conversion_features) &&
+ visitor->Visit("shaderDrawParameterFeatures",
+ &device->shader_draw_parameter_features) &&
+ visitor->Visit("externalFenceProperties",
+ &device->external_fence_properties) &&
+ visitor->Visit("externalSemaphoreProperties",
+ &device->external_semaphore_properties);
+ }
+ if (device->properties.apiVersion >= VK_API_VERSION_1_0) {
+ ret &= visitor->Visit("properties", &device->properties) &&
+ visitor->Visit("features", &device->features) &&
+ visitor->Visit("memory", &device->memory) &&
+ visitor->Visit("queues", &device->queues) &&
+ visitor->Visit("extensions", &device->extensions) &&
+ visitor->Visit("layers", &device->layers) &&
+ visitor->Visit("formats", &device->formats);
+ if (device->ext_driver_properties.reported) {
+ ret &= visitor->Visit("VK_KHR_driver_properties",
+ &device->ext_driver_properties);
+ }
+ if (device->ext_variable_pointer_features.reported) {
+ ret &= visitor->Visit("VK_KHR_variable_pointers",
+ &device->ext_variable_pointer_features);
+ }
+ if (device->ext_shader_float16_int8_features.reported) {
+ ret &= visitor->Visit("VK_KHR_shader_float16_int8",
+ &device->ext_shader_float16_int8_features);
+ }
}
return ret;
}
@@ -897,16 +893,13 @@
template <typename Visitor>
inline bool Iterate(Visitor* visitor, VkJsonInstance* instance) {
bool ret = true;
- switch (instance->api_version ^ VK_VERSION_PATCH(instance->api_version)) {
- case VK_API_VERSION_1_2:
- FALLTHROUGH_INTENDED;
- case VK_API_VERSION_1_1:
- ret &= visitor->Visit("deviceGroups", &instance->device_groups);
- FALLTHROUGH_INTENDED;
- case VK_API_VERSION_1_0:
- ret &= visitor->Visit("layers", &instance->layers) &&
- visitor->Visit("extensions", &instance->extensions) &&
- visitor->Visit("devices", &instance->devices);
+ if (instance->api_version >= VK_API_VERSION_1_1) {
+ ret &= visitor->Visit("deviceGroups", &instance->device_groups);
+ }
+ if (instance->api_version >= VK_API_VERSION_1_0) {
+ ret &= visitor->Visit("layers", &instance->layers) &&
+ visitor->Visit("extensions", &instance->extensions) &&
+ visitor->Visit("devices", &instance->devices);
}
return ret;
}