swapchain: Don't call native_window_get_wide_color_support am: a9e28de9a9
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/2361561
Change-Id: I90737edfb34058017490fb5b3fb86a67285c0842
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/cmds/atrace/README.md b/cmds/atrace/README.md
new file mode 100644
index 0000000..faa43b2
--- /dev/null
+++ b/cmds/atrace/README.md
@@ -0,0 +1,48 @@
+# Atrace categories
+
+The atrace command (and the perfetto configuration) allow listing **categories**
+to select subsets of events to be traced.
+
+Each category can include some userspace events and some ftrace events.
+
+## Vendor categories
+
+It's possible to extend exiting categories (or to define new categories) from
+the /vendor partition in order to add hardware specific ftrace events.
+
+Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt`, atrace
+and perfetto will consider the categories and ftrace events listed there.
+
+The file contains a list of categories, and for each category (on the following
+lines, indented with one or more spaces of time), a list of ftrace events that
+should be enabled when the category is enabled.
+
+Each ftrace event should be a subdirectory in `/sys/kernel/tracing/events/` and
+should be of the form `group/event`. Listing a whole group is not supported,
+each event needs to be listed explicitly.
+
+It is not an error if an ftrace event is listed in the file, but not present on
+the tracing file system.
+
+Example:
+
+```
+gfx
+ mali/gpu_power_state
+ mali/mali_pm_status
+thermal_tj
+ thermal_exynos/thermal_cpu_pressure
+ thermal_exynos/thermal_exynos_arm_update
+```
+
+The file lists two categories (`gfx` and `thermal_tj`). When the `gfx` category
+is enabled, atrace (or perfetto) will enable
+`/sys/kernel/tracing/events/mali/gpu_power_state` and
+`/sys/kernel/tracing/events/mali/mali_pm_status`. When the `thermal_tj` category
+is enabled, atrace (or perfetto) will enable
+`/sys/kernel/tracing/events/thermal_exynos/thermal_cpu_pressure` and
+`/sys/kernel/tracing/events/thermal_exynos/thermal_exynos_arm_update`.
+
+Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt` exists
+on the file system, perfetto and atrace do not query the android.hardware.atrace
+HAL (which is deprecated).
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 48d48ac..8105626 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -49,6 +49,7 @@
#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
+#include <android-base/strings.h>
#include <android-base/stringprintf.h>
using namespace android;
@@ -62,7 +63,7 @@
using std::string;
-#define MAX_SYS_FILES 12
+#define MAX_SYS_FILES 13
const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
@@ -73,7 +74,9 @@
const char* k_pdxServiceCategory = "pdx";
const char* k_coreServicesProp = "ro.atrace.core.services";
-typedef enum { OPT, REQ } requiredness ;
+const char* kVendorCategoriesPath = "/vendor/etc/atrace/atrace_categories.txt";
+
+typedef enum { OPT, REQ } requiredness;
struct TracingCategory {
// The name identifying the category.
@@ -189,6 +192,8 @@
{ OPT, "events/f2fs/f2fs_sync_file_exit/enable" },
{ OPT, "events/f2fs/f2fs_write_begin/enable" },
{ OPT, "events/f2fs/f2fs_write_end/enable" },
+ { OPT, "events/f2fs/f2fs_iostat/enable" },
+ { OPT, "events/f2fs/f2fs_iostat_latency/enable" },
{ OPT, "events/ext4/ext4_da_write_begin/enable" },
{ OPT, "events/ext4/ext4_da_write_end/enable" },
{ OPT, "events/ext4/ext4_sync_file_enter/enable" },
@@ -253,7 +258,20 @@
} },
};
-struct TracingVendorCategory {
+// A category in the vendor categories file.
+struct TracingVendorFileCategory {
+ // The name identifying the category.
+ std::string name;
+
+ // If the category is enabled through command.
+ bool enabled = false;
+
+ // Paths to the ftrace enable files (relative to g_traceFolder).
+ std::vector<std::string> ftrace_enable_paths;
+};
+
+// A category in the vendor HIDL HAL.
+struct TracingVendorHalCategory {
// The name identifying the category.
std::string name;
@@ -263,11 +281,8 @@
// If the category is enabled through command.
bool enabled;
- TracingVendorCategory(string &&name, string &&description, bool enabled)
- : name(std::move(name))
- , description(std::move(description))
- , enabled(enabled)
- {}
+ TracingVendorHalCategory(string&& name, string&& description, bool enabled)
+ : name(std::move(name)), description(std::move(description)), enabled(enabled) {}
};
/* Command line options */
@@ -287,8 +302,9 @@
static bool g_traceAborted = false;
static bool g_categoryEnables[arraysize(k_categories)] = {};
static std::string g_traceFolder;
+static std::vector<TracingVendorFileCategory> g_vendorFileCategories;
static sp<IAtraceDevice> g_atraceHal;
-static std::vector<TracingVendorCategory> g_vendorCategories;
+static std::vector<TracingVendorHalCategory> g_vendorHalCategories;
/* Sys file paths */
static const char* k_traceClockPath =
@@ -645,6 +661,13 @@
}
}
}
+ for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
+ for (const std::string& path : c.ftrace_enable_paths) {
+ if (fileIsWritable(path.c_str())) {
+ ok &= setKernelOptionEnable(path.c_str(), false);
+ }
+ }
+ }
return ok;
}
@@ -724,7 +747,13 @@
static bool setCategoryEnable(const char* name)
{
bool vendor_found = false;
- for (auto &c : g_vendorCategories) {
+ for (auto& c : g_vendorFileCategories) {
+ if (strcmp(name, c.name.c_str()) == 0) {
+ c.enabled = true;
+ vendor_found = true;
+ }
+ }
+ for (auto& c : g_vendorHalCategories) {
if (strcmp(name, c.name.c_str()) == 0) {
c.enabled = true;
vendor_found = true;
@@ -870,6 +899,16 @@
}
}
+ for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
+ if (c.enabled) {
+ for (const std::string& path : c.ftrace_enable_paths) {
+ if (fileIsWritable(path.c_str())) {
+ ok &= setKernelOptionEnable(path.c_str(), true);
+ }
+ }
+ }
+ }
+
return ok;
}
@@ -1055,7 +1094,10 @@
printf(" %10s - %s\n", c.name, c.longname);
}
}
- for (const auto &c : g_vendorCategories) {
+ for (const auto& c : g_vendorFileCategories) {
+ printf(" %10s - (VENDOR)\n", c.name.c_str());
+ }
+ for (const auto& c : g_vendorHalCategories) {
printf(" %10s - %s (HAL)\n", c.name.c_str(), c.description.c_str());
}
}
@@ -1114,8 +1156,38 @@
return true;
}
-void initVendorCategories()
-{
+void initVendorCategoriesFromFile() {
+ std::ifstream is(kVendorCategoriesPath);
+ for (std::string line; std::getline(is, line);) {
+ if (line.empty()) {
+ continue;
+ }
+ if (android::base::StartsWith(line, ' ') || android::base::StartsWith(line, '\t')) {
+ if (g_vendorFileCategories.empty()) {
+ fprintf(stderr, "Malformed vendor categories file\n");
+ exit(1);
+ return;
+ }
+ std::string_view path = std::string_view(line).substr(1);
+ while (android::base::StartsWith(path, ' ') || android::base::StartsWith(path, '\t')) {
+ path.remove_prefix(1);
+ }
+ if (path.empty()) {
+ continue;
+ }
+ std::string enable_path = "events/";
+ enable_path += path;
+ enable_path += "/enable";
+ g_vendorFileCategories.back().ftrace_enable_paths.push_back(std::move(enable_path));
+ } else {
+ TracingVendorFileCategory cat;
+ cat.name = line;
+ g_vendorFileCategories.push_back(std::move(cat));
+ }
+ }
+}
+
+void initVendorCategoriesFromHal() {
g_atraceHal = IAtraceDevice::getService();
if (g_atraceHal == nullptr) {
@@ -1123,27 +1195,34 @@
return;
}
- Return<void> ret = g_atraceHal->listCategories(
- [](const auto& list) {
- g_vendorCategories.reserve(list.size());
- for (const auto& category : list) {
- g_vendorCategories.emplace_back(category.name, category.description, false);
- }
- });
+ Return<void> ret = g_atraceHal->listCategories([](const auto& list) {
+ g_vendorHalCategories.reserve(list.size());
+ for (const auto& category : list) {
+ g_vendorHalCategories.emplace_back(category.name, category.description, false);
+ }
+ });
if (!ret.isOk()) {
fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
}
}
-static bool setUpVendorTracing()
-{
+void initVendorCategories() {
+ // If kVendorCategoriesPath exists on the filesystem, do not use the HAL.
+ if (access(kVendorCategoriesPath, F_OK) != -1) {
+ initVendorCategoriesFromFile();
+ } else {
+ initVendorCategoriesFromHal();
+ }
+}
+
+static bool setUpVendorTracingWithHal() {
if (g_atraceHal == nullptr) {
// No atrace HAL
return true;
}
std::vector<hidl_string> categories;
- for (const auto &c : g_vendorCategories) {
+ for (const auto& c : g_vendorHalCategories) {
if (c.enabled) {
categories.emplace_back(c.name);
}
@@ -1164,15 +1243,14 @@
return true;
}
-static bool cleanUpVendorTracing()
-{
+static bool cleanUpVendorTracingWithHal() {
if (g_atraceHal == nullptr) {
// No atrace HAL
return true;
}
- if (!g_vendorCategories.size()) {
- // No vendor categories
+ if (!g_vendorHalCategories.size()) {
+ // No vendor HAL categories
return true;
}
@@ -1326,7 +1404,7 @@
if (ok && traceStart && !onlyUserspace) {
ok &= setUpKernelTracing();
- ok &= setUpVendorTracing();
+ ok &= setUpVendorTracingWithHal();
ok &= startTrace();
}
@@ -1397,7 +1475,7 @@
if (traceStop) {
cleanUpUserspaceTracing();
if (!onlyUserspace) {
- cleanUpVendorTracing();
+ cleanUpVendorTracingWithHal();
cleanUpKernelTracing();
}
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b1283eb..bb6639e 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -501,10 +501,6 @@
}
static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
- if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
- return true;
- }
-
int32_t uid = multiuser_get_uid(userId, appId);
int shared_app_gid = multiuser_get_shared_gid(userId, appId);
if (shared_app_gid == -1) {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index ee081c4..44ff62b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1475,7 +1475,7 @@
#ifdef BINDER_WITH_KERNEL_IPC
flat_binder_object obj;
obj.hdr.type = BINDER_TYPE_FD;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.flags = 0;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = fd;
obj.cookie = takeOwnership ? 1 : 0;
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index fedc1d9..0d06e9e 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -50,7 +50,8 @@
RpcServer::RpcServer(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {}
RpcServer::~RpcServer() {
- (void)shutdown();
+ RpcMutexUniqueLock _l(mLock);
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Must call shutdown() before destructor");
}
sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
@@ -203,11 +204,15 @@
iovec iov{&zero, sizeof(zero)};
std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds;
- if (receiveMessageFromSocket(server.mServer, &iov, 1, &fds) < 0) {
+ ssize_t num_bytes = receiveMessageFromSocket(server.mServer, &iov, 1, &fds);
+ if (num_bytes < 0) {
int savedErrno = errno;
ALOGE("Failed recvmsg: %s", strerror(savedErrno));
return -savedErrno;
}
+ if (num_bytes == 0) {
+ return DEAD_OBJECT;
+ }
if (fds.size() != 1) {
ALOGE("Expected exactly one fd from recvmsg, got %zu", fds.size());
return -EINVAL;
@@ -242,8 +247,11 @@
socklen_t addrLen = addr.size();
RpcTransportFd clientSocket;
- if (mAcceptFn(*this, &clientSocket) != OK) {
- continue;
+ if ((status = mAcceptFn(*this, &clientSocket)) != OK) {
+ if (status == DEAD_OBJECT)
+ break;
+ else
+ continue;
}
LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 3ec049e..3ebbed6 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -23,6 +23,13 @@
struct AIBinder;
struct ARpcServer;
+struct ARpcSession;
+
+enum class ARpcSession_FileDescriptorTransportMode {
+ None,
+ Unix,
+ Trusty,
+};
// Starts an RPC server on a given port and a given root IBinder object.
// The server will only accept connections from the given CID.
@@ -40,6 +47,22 @@
// could not be started.
[[nodiscard]] ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name);
+// Starts an RPC server that bootstraps sessions using an existing Unix domain
+// socket pair, with a given root IBinder object.
+// Callers should create a pair of SOCK_STREAM Unix domain sockets, pass one to
+// this function and the other to UnixDomainBootstrapClient(). Multiple client
+// session can be created from the client end of the pair.
+// Does not take ownership of `service`.
+// Returns an opaque handle to the running server instance, or null if the server
+// could not be started.
+[[nodiscard]] ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd);
+
+// Sets the list of supported file descriptor transport modes of this RPC server.
+void ARpcServer_setSupportedFileDescriptorTransportModes(
+ ARpcServer* handle,
+ const ARpcSession_FileDescriptorTransportMode modes[],
+ size_t modes_len);
+
// Runs ARpcServer_join() in a background thread. Immediately returns.
void ARpcServer_start(ARpcServer* server);
@@ -50,34 +73,52 @@
void ARpcServer_join(ARpcServer* server);
// Shuts down any running ARpcServer_join().
-void ARpcServer_shutdown(ARpcServer* server);
+[[nodiscard]] bool ARpcServer_shutdown(ARpcServer* server);
// Frees the ARpcServer handle and drops the reference count on the underlying
// RpcServer instance. The handle must not be reused afterwards.
// This automatically calls ARpcServer_shutdown().
void ARpcServer_free(ARpcServer* server);
-// Starts an RPC server on a given port and a given root IBinder factory.
-// RunVsockRpcServerWithFactory acts like RunVsockRpcServerCallback, but instead of
-// assigning single root IBinder object to all connections, factory is called
-// whenever a client connects, making it possible to assign unique IBinder
-// object to each client.
-bool RunVsockRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
- void* factoryContext, unsigned int port);
+// Allocates a new RpcSession object and returns an opaque handle to it.
+[[nodiscard]] ARpcSession* ARpcSession_new();
-AIBinder* VsockRpcClient(unsigned int cid, unsigned int port);
+// Connects to an RPC server over vsock at a given CID on a given port.
+// Returns the root Binder object of the server.
+AIBinder* ARpcSession_setupVsockClient(ARpcSession* session, unsigned int cid,
+ unsigned int port);
-// Gets the service via the RPC binder with Unix domain socket with the given
-// Unix socket `name`.
-// The final Unix domain socket path name is /dev/socket/`name`.
-AIBinder* UnixDomainRpcClient(const char* name);
+// Connects to an RPC server over a Unix Domain Socket of the given name.
+// The final Unix Domain Socket path name is /dev/socket/`name`.
+// Returns the root Binder object of the server.
+AIBinder* ARpcSession_setupUnixDomainClient(ARpcSession* session, const char* name);
-// Connect to an RPC server with preconnected file descriptors.
+// Connects to an RPC server over the given bootstrap Unix domain socket.
+// Does NOT take ownership of `bootstrapFd`.
+AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* session,
+ int bootstrapFd);
+
+// Connects to an RPC server with preconnected file descriptors.
//
// requestFd should connect to the server and return a valid file descriptor, or
// -1 if connection fails.
//
// param will be passed to requestFd. Callers can use param to pass contexts to
// the requestFd function.
-AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param);
+AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* session,
+ int (*requestFd)(void* param),
+ void* param);
+
+// Sets the file descriptor transport mode for this session.
+void ARpcSession_setFileDescriptorTransportMode(ARpcSession* session,
+ ARpcSession_FileDescriptorTransportMode mode);
+
+// Sets the maximum number of incoming threads.
+void ARpcSession_setMaxIncomingThreads(ARpcSession* session, size_t threads);
+
+// Sets the maximum number of outgoing threads.
+void ARpcSession_setMaxOutgoingThreads(ARpcSession* session, size_t threads);
+
+// Decrements the refcount of the underlying RpcSession object.
+void ARpcSession_free(ARpcSession* session);
}
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 88f8c94..78dae4b 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -35,51 +35,46 @@
// Opaque handle for RpcServer.
struct ARpcServer {};
-static sp<RpcServer> toRpcServer(ARpcServer* handle) {
- auto ref = reinterpret_cast<RpcServer*>(handle);
- return sp<RpcServer>::fromExisting(ref);
-}
+// Opaque handle for RpcSession.
+struct ARpcSession {};
-static ARpcServer* createRpcServerHandle(sp<RpcServer>& server) {
+template <typename A, typename T>
+static A* createObjectHandle(sp<T>& server) {
auto ref = server.get();
ref->incStrong(ref);
- return reinterpret_cast<ARpcServer*>(ref);
+ return reinterpret_cast<A*>(ref);
}
-static void freeRpcServerHandle(ARpcServer* handle) {
- auto ref = reinterpret_cast<RpcServer*>(handle);
+template <typename T, typename A>
+static void freeObjectHandle(A* handle) {
+ LOG_ALWAYS_FATAL_IF(handle == nullptr, "Handle cannot be null");
+ auto ref = reinterpret_cast<T*>(handle);
ref->decStrong(ref);
}
-static unsigned int cidFromStructAddr(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 vaddr->svm_cid;
+template <typename T, typename A>
+static sp<T> handleToStrongPointer(A* handle) {
+ LOG_ALWAYS_FATAL_IF(handle == nullptr, "Handle cannot be null");
+ auto ref = reinterpret_cast<T*>(handle);
+ return sp<T>::fromExisting(ref);
+}
+
+RpcSession::FileDescriptorTransportMode toTransportMode(
+ ARpcSession_FileDescriptorTransportMode mode) {
+ switch (mode) {
+ case ARpcSession_FileDescriptorTransportMode::None:
+ return RpcSession::FileDescriptorTransportMode::NONE;
+ case ARpcSession_FileDescriptorTransportMode::Unix:
+ return RpcSession::FileDescriptorTransportMode::UNIX;
+ case ARpcSession_FileDescriptorTransportMode::Trusty:
+ return RpcSession::FileDescriptorTransportMode::TRUSTY;
+ default:
+ return RpcSession::FileDescriptorTransportMode::NONE;
+ }
}
extern "C" {
-bool RunVsockRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
- void* factoryContext, unsigned int port) {
- auto server = RpcServer::make();
- if (status_t status = server->setupVsockServer(VMADDR_CID_ANY, port); status != OK) {
- LOG(ERROR) << "Failed to set up vsock server with port " << port
- << " error: " << statusToString(status).c_str();
- return false;
- }
- server->setPerSessionRootObject([=](const void* addr, size_t addrlen) {
- unsigned int cid = cidFromStructAddr(addr, addrlen);
- return AIBinder_toPlatformBinder(factory(cid, factoryContext));
- });
-
- server->join();
-
- // Shutdown any open sessions since server failed.
- (void)server->shutdown();
- return true;
-}
-
ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port) {
auto server = RpcServer::make();
@@ -96,16 +91,18 @@
}
if (cid != VMADDR_CID_ANY) {
server->setConnectionFilter([=](const void* addr, size_t addrlen) {
- unsigned int remoteCid = cidFromStructAddr(addr, addrlen);
- if (cid != remoteCid) {
- LOG(ERROR) << "Rejected vsock connection from CID " << remoteCid;
+ 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");
+ if (cid != vaddr->svm_cid) {
+ LOG(ERROR) << "Rejected vsock connection from CID " << vaddr->svm_cid;
return false;
}
return true;
});
}
server->setRootObject(AIBinder_toPlatformBinder(service));
- return createRpcServerHandle(server);
+ return createObjectHandle<ARpcServer>(server);
}
ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name) {
@@ -121,27 +118,67 @@
return nullptr;
}
server->setRootObject(AIBinder_toPlatformBinder(service));
- return createRpcServerHandle(server);
+ return createObjectHandle<ARpcServer>(server);
+}
+
+ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd) {
+ auto server = RpcServer::make();
+ auto fd = unique_fd(bootstrapFd);
+ if (!fd.ok()) {
+ LOG(ERROR) << "Invalid bootstrap fd " << bootstrapFd;
+ return nullptr;
+ }
+ if (status_t status = server->setupUnixDomainSocketBootstrapServer(std::move(fd));
+ status != OK) {
+ LOG(ERROR) << "Failed to set up Unix Domain RPC server with bootstrap fd " << bootstrapFd
+ << " error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ server->setRootObject(AIBinder_toPlatformBinder(service));
+ return createObjectHandle<ARpcServer>(server);
+}
+
+void ARpcServer_setSupportedFileDescriptorTransportModes(
+ ARpcServer* handle, const ARpcSession_FileDescriptorTransportMode modes[],
+ size_t modes_len) {
+ auto server = handleToStrongPointer<RpcServer>(handle);
+ std::vector<RpcSession::FileDescriptorTransportMode> modevec;
+ for (size_t i = 0; i < modes_len; i++) {
+ modevec.push_back(toTransportMode(modes[i]));
+ }
+ server->setSupportedFileDescriptorTransportModes(modevec);
}
void ARpcServer_start(ARpcServer* handle) {
- toRpcServer(handle)->start();
+ handleToStrongPointer<RpcServer>(handle)->start();
}
void ARpcServer_join(ARpcServer* handle) {
- toRpcServer(handle)->join();
+ handleToStrongPointer<RpcServer>(handle)->join();
}
-void ARpcServer_shutdown(ARpcServer* handle) {
- toRpcServer(handle)->shutdown();
+bool ARpcServer_shutdown(ARpcServer* handle) {
+ return handleToStrongPointer<RpcServer>(handle)->shutdown();
}
void ARpcServer_free(ARpcServer* handle) {
- freeRpcServerHandle(handle);
+ // Ignore the result of ARpcServer_shutdown - either it had been called
+ // earlier, or the RpcServer destructor will panic.
+ (void)ARpcServer_shutdown(handle);
+ freeObjectHandle<RpcServer>(handle);
}
-AIBinder* VsockRpcClient(unsigned int cid, unsigned int port) {
+ARpcSession* ARpcSession_new() {
auto session = RpcSession::make();
+ return createObjectHandle<ARpcSession>(session);
+}
+
+void ARpcSession_free(ARpcSession* handle) {
+ freeObjectHandle<RpcSession>(handle);
+}
+
+AIBinder* ARpcSession_setupVsockClient(ARpcSession* handle, unsigned int cid, unsigned int port) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
if (status_t status = session->setupVsockClient(cid, port); status != OK) {
LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port
<< " error: " << statusToString(status).c_str();
@@ -150,10 +187,10 @@
return AIBinder_fromPlatformBinder(session->getRootObject());
}
-AIBinder* UnixDomainRpcClient(const char* name) {
+AIBinder* ARpcSession_setupUnixDomainClient(ARpcSession* handle, const char* name) {
std::string pathname(name);
pathname = ANDROID_SOCKET_DIR "/" + pathname;
- auto session = RpcSession::make();
+ auto session = handleToStrongPointer<RpcSession>(handle);
if (status_t status = session->setupUnixDomainClient(pathname.c_str()); status != OK) {
LOG(ERROR) << "Failed to set up Unix Domain RPC client with path: " << pathname
<< " error: " << statusToString(status).c_str();
@@ -162,8 +199,25 @@
return AIBinder_fromPlatformBinder(session->getRootObject());
}
-AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param) {
- auto session = RpcSession::make();
+AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* handle, int bootstrapFd) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ auto fd = unique_fd(dup(bootstrapFd));
+ if (!fd.ok()) {
+ LOG(ERROR) << "Invalid bootstrap fd " << bootstrapFd;
+ return nullptr;
+ }
+ if (status_t status = session->setupUnixDomainSocketBootstrapClient(std::move(fd));
+ status != OK) {
+ LOG(ERROR) << "Failed to set up Unix Domain RPC client with bootstrap fd: " << bootstrapFd
+ << " error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
+AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* handle, int (*requestFd)(void* param),
+ void* param) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
auto request = [=] { return unique_fd{requestFd(param)}; };
if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
LOG(ERROR) << "Failed to set up vsock client. error: " << statusToString(status).c_str();
@@ -171,4 +225,20 @@
}
return AIBinder_fromPlatformBinder(session->getRootObject());
}
+
+void ARpcSession_setFileDescriptorTransportMode(ARpcSession* handle,
+ ARpcSession_FileDescriptorTransportMode mode) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ session->setFileDescriptorTransportMode(toTransportMode(mode));
+}
+
+void ARpcSession_setMaxIncomingThreads(ARpcSession* handle, size_t threads) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ session->setMaxIncomingThreads(threads);
+}
+
+void ARpcSession_setMaxOutgoingThreads(ARpcSession* handle, size_t threads) {
+ auto session = handleToStrongPointer<RpcSession>(handle);
+ session->setMaxOutgoingThreads(threads);
+}
}
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index f70ebfc..afb73e9 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -68,10 +68,13 @@
visibility: [":__subpackages__"],
source_stem: "bindings",
bindgen_flags: [
+ "--size_t-is-usize",
"--blocklist-type",
"AIBinder",
"--raw-line",
"use binder_ndk_sys::AIBinder;",
+ "--rustified-enum",
+ "ARpcSession_FileDescriptorTransportMode",
],
rustlibs: [
"libbinder_ndk_sys",
diff --git a/libs/binder/rust/rpcbinder/src/client.rs b/libs/binder/rust/rpcbinder/src/client.rs
deleted file mode 100644
index 48c787b..0000000
--- a/libs/binder/rust/rpcbinder/src/client.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.
- */
-
-use binder::{unstable_api::new_spibinder, FromIBinder, SpIBinder, StatusCode, Strong};
-use std::ffi::CString;
-use std::os::{
- raw::{c_int, c_void},
- unix::io::RawFd,
-};
-
-/// Connects to an RPC Binder server over vsock.
-pub fn get_vsock_rpc_service(cid: u32, port: u32) -> Option<SpIBinder> {
- // SAFETY: AIBinder returned by VsockRpcClient has correct reference count,
- // and the ownership can safely be taken by new_spibinder.
- unsafe { new_spibinder(binder_rpc_unstable_bindgen::VsockRpcClient(cid, port)) }
-}
-
-/// Connects to an RPC Binder server for a particular interface over vsock.
-pub fn get_vsock_rpc_interface<T: FromIBinder + ?Sized>(
- cid: u32,
- port: u32,
-) -> Result<Strong<T>, StatusCode> {
- interface_cast(get_vsock_rpc_service(cid, port))
-}
-
-/// Connects to an RPC Binder server over Unix domain socket.
-pub fn get_unix_domain_rpc_service(socket_name: &str) -> Option<SpIBinder> {
- let socket_name = match CString::new(socket_name) {
- Ok(s) => s,
- Err(e) => {
- log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
- return None;
- }
- };
- // SAFETY: AIBinder returned by UnixDomainRpcClient has correct reference count,
- // and the ownership can safely be taken by new_spibinder.
- unsafe { new_spibinder(binder_rpc_unstable_bindgen::UnixDomainRpcClient(socket_name.as_ptr())) }
-}
-
-/// Connects to an RPC Binder server for a particular interface over Unix domain socket.
-pub fn get_unix_domain_rpc_interface<T: FromIBinder + ?Sized>(
- socket_name: &str,
-) -> Result<Strong<T>, StatusCode> {
- interface_cast(get_unix_domain_rpc_service(socket_name))
-}
-
-/// Connects to an RPC Binder server, using the given callback to get (and take ownership of)
-/// file descriptors already connected to it.
-pub fn get_preconnected_rpc_service(
- mut request_fd: impl FnMut() -> Option<RawFd>,
-) -> Option<SpIBinder> {
- // Double reference the factory because trait objects aren't FFI safe.
- let mut request_fd_ref: RequestFd = &mut request_fd;
- let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
-
- // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
- // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
- // of param, only passing it to request_fd_wrapper.
- unsafe {
- new_spibinder(binder_rpc_unstable_bindgen::RpcPreconnectedClient(
- Some(request_fd_wrapper),
- param,
- ))
- }
-}
-
-type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
-
-unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
- // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
- // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
- // initialized instance.
- let request_fd_ptr = param as *mut RequestFd;
- let request_fd = request_fd_ptr.as_mut().unwrap();
- if let Some(fd) = request_fd() {
- fd
- } else {
- -1
- }
-}
-
-/// Connects to an RPC Binder server for a particular interface, using the given callback to get
-/// (and take ownership of) file descriptors already connected to it.
-pub fn get_preconnected_rpc_interface<T: FromIBinder + ?Sized>(
- request_fd: impl FnMut() -> Option<RawFd>,
-) -> Result<Strong<T>, StatusCode> {
- interface_cast(get_preconnected_rpc_service(request_fd))
-}
-
-fn interface_cast<T: FromIBinder + ?Sized>(
- service: Option<SpIBinder>,
-) -> Result<Strong<T>, StatusCode> {
- if let Some(service) = service {
- FromIBinder::try_from(service)
- } else {
- Err(StatusCode::NAME_NOT_FOUND)
- }
-}
diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs
index 1b719aa..a957385 100644
--- a/libs/binder/rust/rpcbinder/src/lib.rs
+++ b/libs/binder/rust/rpcbinder/src/lib.rs
@@ -16,11 +16,8 @@
//! API for RPC Binder services.
-mod client;
mod server;
+mod session;
-pub use client::{
- get_preconnected_rpc_interface, get_preconnected_rpc_service, get_unix_domain_rpc_interface,
- get_unix_domain_rpc_service, get_vsock_rpc_interface, get_vsock_rpc_service,
-};
-pub use server::{run_vsock_rpc_server_with_factory, RpcServer, RpcServerRef};
+pub use server::{RpcServer, RpcServerRef};
+pub use session::{FileDescriptorTransportMode, RpcSession, RpcSessionRef};
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index d5f1219..761b306 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-use binder::{
- unstable_api::{AIBinder, AsNative},
- SpIBinder,
-};
+use crate::session::FileDescriptorTransportMode;
+use binder::{unstable_api::AsNative, SpIBinder};
use binder_rpc_unstable_bindgen::ARpcServer;
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
+use std::ffi::CString;
use std::io::{Error, ErrorKind};
-use std::{ffi::CString, os::raw, ptr::null_mut};
+use std::os::unix::io::{IntoRawFd, OwnedFd};
foreign_type! {
type CType = binder_rpc_unstable_bindgen::ARpcServer;
@@ -82,6 +81,27 @@
}
}
+ /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
+ /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
+ /// domain sockets, pass one to the server and the other to the client. Multiple client session
+ /// can be created from the client end of the pair.
+ pub fn new_unix_domain_bootstrap(
+ mut service: SpIBinder,
+ bootstrap_fd: OwnedFd,
+ ) -> Result<RpcServer, Error> {
+ let service = service.as_native_mut();
+
+ // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+ // Plus the binder objects are threadsafe.
+ // The server takes ownership of the bootstrap FD.
+ unsafe {
+ Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
+ service,
+ bootstrap_fd.into_raw_fd(),
+ ))
+ }
+ }
+
unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
if ptr.is_null() {
return Err(Error::new(ErrorKind::Other, "Failed to start server"));
@@ -91,6 +111,22 @@
}
impl RpcServerRef {
+ /// Sets the list of file descriptor transport modes supported by this server.
+ pub fn set_supported_file_descriptor_transport_modes(
+ &self,
+ modes: &[FileDescriptorTransportMode],
+ ) {
+ // SAFETY - Does not keep the pointer after returning does, nor does it
+ // read past its boundary. Only passes the 'self' pointer as an opaque handle.
+ unsafe {
+ binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
+ self.as_ptr(),
+ modes.as_ptr(),
+ modes.len(),
+ )
+ }
+ }
+
/// Starts a new background thread and calls join(). Returns immediately.
pub fn start(&self) {
unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
@@ -104,51 +140,11 @@
/// Shuts down the running RpcServer. Can be called multiple times and from
/// multiple threads. Called automatically during drop().
- pub fn shutdown(&self) {
- unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) };
- }
-}
-
-type RpcServerFactoryRef<'a> = &'a mut (dyn FnMut(u32) -> Option<SpIBinder> + Send + Sync);
-
-/// Runs a binder RPC server, using the given factory function to construct a binder service
-/// implementation for each connection.
-///
-/// The current thread is joined to the binder thread pool to handle incoming messages.
-///
-/// Returns true if the server has shutdown normally, false if it failed in some way.
-pub fn run_vsock_rpc_server_with_factory(
- port: u32,
- mut factory: impl FnMut(u32) -> Option<SpIBinder> + Send + Sync,
-) -> bool {
- // Double reference the factory because trait objects aren't FFI safe.
- // NB: The type annotation is necessary to ensure that we have a `dyn` rather than an `impl`.
- let mut factory_ref: RpcServerFactoryRef = &mut factory;
- let context = &mut factory_ref as *mut RpcServerFactoryRef as *mut raw::c_void;
-
- // SAFETY: `factory_wrapper` is only ever called by `RunVsockRpcServerWithFactory`, with context
- // taking the pointer value above (so a properly aligned non-null pointer to an initialized
- // `RpcServerFactoryRef`), within the lifetime of `factory_ref` (i.e. no more calls will be made
- // after `RunVsockRpcServerWithFactory` returns).
- unsafe {
- binder_rpc_unstable_bindgen::RunVsockRpcServerWithFactory(
- Some(factory_wrapper),
- context,
- port,
- )
- }
-}
-
-unsafe extern "C" fn factory_wrapper(cid: u32, context: *mut raw::c_void) -> *mut AIBinder {
- // SAFETY: `context` was created from an `&mut RpcServerFactoryRef` by
- // `run_vsock_rpc_server_with_factory`, and we are still within the lifetime of the value it is
- // pointing to.
- let factory_ptr = context as *mut RpcServerFactoryRef;
- let factory = factory_ptr.as_mut().unwrap();
-
- if let Some(mut service) = factory(cid) {
- service.as_native_mut()
- } else {
- null_mut()
+ pub fn shutdown(&self) -> Result<(), Error> {
+ if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
+ Ok(())
+ } else {
+ Err(Error::from(ErrorKind::UnexpectedEof))
+ }
}
}
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
new file mode 100644
index 0000000..62fedb1
--- /dev/null
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+use binder::unstable_api::new_spibinder;
+use binder::{FromIBinder, SpIBinder, StatusCode, Strong};
+use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
+use std::ffi::CString;
+use std::os::{
+ raw::{c_int, c_void},
+ unix::io::{AsRawFd, BorrowedFd, RawFd},
+};
+
+pub use binder_rpc_unstable_bindgen::ARpcSession_FileDescriptorTransportMode as FileDescriptorTransportMode;
+
+foreign_type! {
+ type CType = binder_rpc_unstable_bindgen::ARpcSession;
+ fn drop = binder_rpc_unstable_bindgen::ARpcSession_free;
+
+ /// A type that represents a foreign instance of RpcSession.
+ #[derive(Debug)]
+ pub struct RpcSession;
+ /// A borrowed RpcSession.
+ pub struct RpcSessionRef;
+}
+
+/// SAFETY - The opaque handle can be cloned freely.
+unsafe impl Send for RpcSession {}
+/// SAFETY - The underlying C++ RpcSession class is thread-safe.
+unsafe impl Sync for RpcSession {}
+
+impl RpcSession {
+ /// Allocates a new RpcSession object.
+ pub fn new() -> RpcSession {
+ // SAFETY - Takes ownership of the returned handle, which has correct refcount.
+ unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) }
+ }
+}
+
+impl Default for RpcSession {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl RpcSessionRef {
+ /// Sets the file descriptor transport mode for this session.
+ pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) {
+ // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ unsafe {
+ binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode(
+ self.as_ptr(),
+ mode,
+ )
+ };
+ }
+
+ /// Sets the maximum number of incoming threads.
+ pub fn set_max_incoming_threads(&self, threads: usize) {
+ // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ unsafe {
+ binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads)
+ };
+ }
+
+ /// Sets the maximum number of outgoing threads.
+ pub fn set_max_outgoing_threads(&self, threads: usize) {
+ // SAFETY - Only passes the 'self' pointer as an opaque handle.
+ unsafe {
+ binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingThreads(self.as_ptr(), threads)
+ };
+ }
+
+ /// Connects to an RPC Binder server over vsock for a particular interface.
+ pub fn setup_vsock_client<T: FromIBinder + ?Sized>(
+ &self,
+ cid: u32,
+ port: u32,
+ ) -> Result<Strong<T>, StatusCode> {
+ // SAFETY: AIBinder returned by ARpcSession_setupVsockClient has correct
+ // reference count, and the ownership can safely be taken by new_spibinder.
+ let service = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupVsockClient(
+ self.as_ptr(),
+ cid,
+ port,
+ ))
+ };
+ Self::get_interface(service)
+ }
+
+ /// Connects to an RPC Binder server over a names Unix Domain Socket for
+ /// a particular interface.
+ pub fn setup_unix_domain_client<T: FromIBinder + ?Sized>(
+ &self,
+ socket_name: &str,
+ ) -> Result<Strong<T>, StatusCode> {
+ let socket_name = match CString::new(socket_name) {
+ Ok(s) => s,
+ Err(e) => {
+ log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+ return Err(StatusCode::NAME_NOT_FOUND);
+ }
+ };
+
+ // SAFETY: AIBinder returned by ARpcSession_setupUnixDomainClient has correct
+ // reference count, and the ownership can safely be taken by new_spibinder.
+ let service = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainClient(
+ self.as_ptr(),
+ socket_name.as_ptr(),
+ ))
+ };
+ Self::get_interface(service)
+ }
+
+ /// Connects to an RPC Binder server over a bootstrap Unix Domain Socket
+ /// for a particular interface.
+ pub fn setup_unix_domain_bootstrap_client<T: FromIBinder + ?Sized>(
+ &self,
+ bootstrap_fd: BorrowedFd,
+ ) -> Result<Strong<T>, StatusCode> {
+ // SAFETY: ARpcSession_setupUnixDomainBootstrapClient does not take
+ // ownership of bootstrap_fd. The returned AIBinder has correct
+ // reference count, and the ownership can safely be taken by new_spibinder.
+ let service = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainBootstrapClient(
+ self.as_ptr(),
+ bootstrap_fd.as_raw_fd(),
+ ))
+ };
+ Self::get_interface(service)
+ }
+
+ /// Connects to an RPC Binder server, using the given callback to get (and
+ /// take ownership of) file descriptors already connected to it.
+ pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(
+ &self,
+ mut request_fd: impl FnMut() -> Option<RawFd>,
+ ) -> Result<Strong<T>, StatusCode> {
+ // Double reference the factory because trait objects aren't FFI safe.
+ let mut request_fd_ref: RequestFd = &mut request_fd;
+ let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
+
+ // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
+ // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
+ // of param, only passing it to request_fd_wrapper.
+ let service = unsafe {
+ new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupPreconnectedClient(
+ self.as_ptr(),
+ Some(request_fd_wrapper),
+ param,
+ ))
+ };
+ Self::get_interface(service)
+ }
+
+ fn get_interface<T: FromIBinder + ?Sized>(
+ service: Option<SpIBinder>,
+ ) -> Result<Strong<T>, StatusCode> {
+ if let Some(service) = service {
+ FromIBinder::try_from(service)
+ } else {
+ Err(StatusCode::NAME_NOT_FOUND)
+ }
+ }
+}
+
+type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
+
+unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
+ // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
+ // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
+ // initialized instance.
+ let request_fd_ptr = param as *mut RequestFd;
+ let request_fd = request_fd_ptr.as_mut().unwrap();
+ request_fd().unwrap_or(-1)
+}
diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp
index fe28454..410a5af 100644
--- a/services/stats/StatsAidl.cpp
+++ b/services/stats/StatsAidl.cpp
@@ -69,6 +69,10 @@
case VendorAtomValue::repeatedIntValue: {
const std::optional<std::vector<int>>& repeatedIntValue =
atomValue.get<VendorAtomValue::repeatedIntValue>();
+ if (!repeatedIntValue) {
+ AStatsEvent_writeInt32Array(event, {}, 0);
+ break;
+ }
AStatsEvent_writeInt32Array(event, repeatedIntValue->data(),
repeatedIntValue->size());
break;
@@ -76,6 +80,10 @@
case VendorAtomValue::repeatedLongValue: {
const std::optional<std::vector<int64_t>>& repeatedLongValue =
atomValue.get<VendorAtomValue::repeatedLongValue>();
+ if (!repeatedLongValue) {
+ AStatsEvent_writeInt64Array(event, {}, 0);
+ break;
+ }
AStatsEvent_writeInt64Array(event, repeatedLongValue->data(),
repeatedLongValue->size());
break;
@@ -83,6 +91,10 @@
case VendorAtomValue::repeatedFloatValue: {
const std::optional<std::vector<float>>& repeatedFloatValue =
atomValue.get<VendorAtomValue::repeatedFloatValue>();
+ if (!repeatedFloatValue) {
+ AStatsEvent_writeFloatArray(event, {}, 0);
+ break;
+ }
AStatsEvent_writeFloatArray(event, repeatedFloatValue->data(),
repeatedFloatValue->size());
break;
@@ -90,12 +102,18 @@
case VendorAtomValue::repeatedStringValue: {
const std::optional<std::vector<std::optional<std::string>>>& repeatedStringValue =
atomValue.get<VendorAtomValue::repeatedStringValue>();
+ if (!repeatedStringValue) {
+ AStatsEvent_writeStringArray(event, {}, 0);
+ break;
+ }
const std::vector<std::optional<std::string>>& repeatedStringVector =
*repeatedStringValue;
const char* cStringArray[repeatedStringVector.size()];
for (int i = 0; i < repeatedStringVector.size(); ++i) {
- cStringArray[i] = repeatedStringVector[i]->c_str();
+ cStringArray[i] = repeatedStringVector[i].has_value()
+ ? repeatedStringVector[i]->c_str()
+ : "";
}
AStatsEvent_writeStringArray(event, cStringArray, repeatedStringVector.size());
@@ -104,6 +122,10 @@
case VendorAtomValue::repeatedBoolValue: {
const std::optional<std::vector<bool>>& repeatedBoolValue =
atomValue.get<VendorAtomValue::repeatedBoolValue>();
+ if (!repeatedBoolValue) {
+ AStatsEvent_writeBoolArray(event, {}, 0);
+ break;
+ }
const std::vector<bool>& repeatedBoolVector = *repeatedBoolValue;
bool boolArray[repeatedBoolValue->size()];
@@ -117,7 +139,10 @@
case VendorAtomValue::byteArrayValue: {
const std::optional<std::vector<uint8_t>>& byteArrayValue =
atomValue.get<VendorAtomValue::byteArrayValue>();
-
+ if (!byteArrayValue) {
+ AStatsEvent_writeByteArray(event, {}, 0);
+ break;
+ }
AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size());
break;
}
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index da6b00a..0284192 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -731,7 +731,7 @@
visitor->Visit("vulkanMemoryModelAvailabilityVisibilityChains", &features->vulkanMemoryModelAvailabilityVisibilityChains) &&
visitor->Visit("shaderOutputViewportIndex", &features->shaderOutputViewportIndex) &&
visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer) &&
- visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer);
+ visitor->Visit("subgroupBroadcastDynamicId", &features->subgroupBroadcastDynamicId);
}
template <typename Visitor>