Merge "Remove libsurfaceflinger_unittest from root TEST_MAPPING"
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index d09d3e8..18c267d 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -47,6 +47,9 @@
"libutils",
"server_configurable_flags",
],
+ static_libs: [
+ "libasync_safe",
+ ],
export_shared_lib_headers: [
"libbinder",
],
@@ -251,6 +254,7 @@
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libotapreoptparameters",
],
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 0cf50a3..204953c 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -36,6 +36,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <async_safe/log.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
@@ -727,7 +728,8 @@
if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
if (errno != EWOULDBLOCK) {
- PLOG(WARNING) << "Error locking profile " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error locking profile %s: %d",
+ package_name.c_str(), errno);
}
// This implies that the app owning this profile is running
// (and has acquired the lock).
@@ -735,13 +737,15 @@
// The app never acquires the lock for the reference profiles of primary apks.
// Only dex2oat from installd will do that. Since installd is single threaded
// we should not see this case. Nevertheless be prepared for it.
- PLOG(WARNING) << "Failed to flock " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Failed to flock %s: %d",
+ package_name.c_str(), errno);
return false;
}
bool truncated = ftruncate(out_fd.get(), 0) == 0;
if (!truncated) {
- PLOG(WARNING) << "Could not truncate " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Could not truncate %s: %d",
+ package_name.c_str(), errno);
}
// Copy over data.
@@ -755,7 +759,8 @@
write(out_fd.get(), buffer, bytes);
}
if (flock(out_fd.get(), LOCK_UN) != 0) {
- PLOG(WARNING) << "Error unlocking profile " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error unlocking profile %s: %d",
+ package_name.c_str(), errno);
}
// Use _exit since we don't want to run the global destructors in the child.
// b/62597429
@@ -1513,7 +1518,8 @@
// Validate the path structure.
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
}
@@ -1809,7 +1815,8 @@
drop_capabilities(uid);
if (flock(out_oat.fd(), LOCK_EX | LOCK_NB) != 0) {
- PLOG(ERROR) << "flock(" << out_oat.path() << ") failed";
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "flock(%s) failed",
+ out_oat.path().c_str());
_exit(DexoptReturnCodes::kFlock);
}
@@ -1904,7 +1911,8 @@
const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr;
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(kReconcileSecondaryDexValidationError);
}
@@ -1917,7 +1925,8 @@
case kSecondaryDexAccessIOError: _exit(kReconcileSecondaryDexAccessIOError);
case kSecondaryDexAccessPermissionError: _exit(kReconcileSecondaryDexValidationError);
default:
- LOG(ERROR) << "Unexpected result from check_secondary_dex_access: " << access_check;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Unexpected result from check_secondary_dex_access: %d", access_check);
_exit(kReconcileSecondaryDexValidationError);
}
@@ -1930,7 +1939,7 @@
std::string error_msg;
if (!create_secondary_dex_oat_layout(
dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
- LOG(ERROR) << error_msg;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "%s", error_msg.c_str());
_exit(kReconcileSecondaryDexValidationError);
}
@@ -1957,7 +1966,8 @@
result = rmdir_if_empty(oat_dir) && result;
}
if (!result) {
- PLOG(ERROR) << "Failed to clean secondary dex artifacts for location " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
}
_exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
}
@@ -2030,7 +2040,8 @@
pipe_read.reset();
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(DexoptReturnCodes::kHashValidatePath);
}
@@ -2041,6 +2052,8 @@
_exit(0);
}
PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Failed to open secondary dex %s: %d", dex_path.c_str(), errno);
_exit(DexoptReturnCodes::kHashOpenPath);
}
@@ -2053,7 +2066,8 @@
if (bytes_read == 0) {
break;
} else if (bytes_read == -1) {
- PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Failed to read secondary dex %s: %d", dex_path.c_str(), errno);
_exit(DexoptReturnCodes::kHashReadDex);
}
diff --git a/cmds/installd/file_parsing.h b/cmds/installd/file_parsing.h
index 3e2f815..88801ca 100644
--- a/cmds/installd/file_parsing.h
+++ b/cmds/installd/file_parsing.h
@@ -19,18 +19,14 @@
#include <fstream>
#include <functional>
-#include <string>
+#include <string_view>
+#include "android-base/unique_fd.h"
namespace android {
namespace installd {
-bool ParseFile(const std::string& strFile, std::function<bool (const std::string&)> parse) {
- std::ifstream input_stream(strFile);
-
- if (!input_stream.is_open()) {
- return false;
- }
-
+template<typename Func>
+bool ParseFile(std::istream& input_stream, Func parse) {
while (!input_stream.eof()) {
// Read the next line.
std::string line;
@@ -54,6 +50,15 @@
return true;
}
+template<typename Func>
+bool ParseFile(std::string_view str_file, Func parse) {
+ std::ifstream ifs(str_file);
+ if (!ifs.is_open()) {
+ return false;
+ }
+ return ParseFile(ifs, parse);
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index ed31ad9..6aa32b8 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -26,6 +26,7 @@
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -36,6 +37,7 @@
#include <log/log.h>
#include <private/android_filesystem_config.h>
+#include "android-base/file.h"
#include "dexopt.h"
#include "file_parsing.h"
#include "globals.h"
@@ -195,38 +197,63 @@
// export NAME VALUE
// For simplicity, don't respect string quotation. The values we are interested in can be
// encoded without them.
- // init.environ.rc and etc/classpath have the same format for
- // environment variable exports and can be matched by the same regex.
+ //
+ // init.environ.rc and derive_classpath all have the same format for
+ // environment variable exports (since they are all meant to be read by
+ // init) and can be matched by the same regex.
+
+ std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
+ auto parse_results = [&](auto& input) {
+ ParseFile(input, [&](const std::string& line) {
+ std::smatch export_match;
+ if (!std::regex_match(line, export_match, export_regex)) {
+ return true;
+ }
+
+ if (export_match.size() != 3) {
+ return true;
+ }
+
+ std::string name = export_match[1].str();
+ std::string value = export_match[2].str();
+
+ system_properties_.SetProperty(name, value);
+
+ return true;
+ });
+ };
+
// TODO Just like with the system-properties above we really should have
// common code between init and otapreopt to deal with reading these
// things. See b/181182967
+ // There have been a variety of places the various env-vars have been
+ // over the years. Expand or reduce this list as needed.
static constexpr const char* kEnvironmentVariableSources[] = {
- "/init.environ.rc", "/etc/classpath"
+ "/init.environ.rc",
};
-
- std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
+ // First get everything from the static files.
for (const char* env_vars_file : kEnvironmentVariableSources) {
- bool parse_result = ParseFile(env_vars_file, [&](const std::string& line) {
- std::smatch export_match;
- if (!std::regex_match(line, export_match, export_regex)) {
- return true;
- }
-
- if (export_match.size() != 3) {
- return true;
- }
-
- std::string name = export_match[1].str();
- std::string value = export_match[2].str();
-
- system_properties_.SetProperty(name, value);
-
- return true;
- });
- if (!parse_result) {
- return false;
- }
+ parse_results(env_vars_file);
}
+
+ // Next get everything from derive_classpath, since we're already in the
+ // chroot it will get the new versions of any dependencies.
+ {
+ android::base::unique_fd fd(memfd_create("derive_classpath_temp", MFD_CLOEXEC));
+ if (!fd.ok()) {
+ LOG(ERROR) << "Unable to create fd for derive_classpath";
+ return false;
+ }
+ std::string memfd_file = StringPrintf("/proc/%d/fd/%d", getpid(), fd.get());
+ std::string error_msg;
+ if (!Exec({"/apex/com.android.sdkext/bin/derive_classpath", memfd_file}, &error_msg)) {
+ PLOG(ERROR) << "Running derive_classpath failed: " << error_msg;
+ return false;
+ }
+ std::ifstream ifs(memfd_file);
+ parse_results(ifs);
+ }
+
if (system_properties_.GetProperty(kAndroidDataPathPropertyName) == nullptr) {
return false;
}
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 83f01de..c62734a 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -275,6 +275,7 @@
static constexpr const std::string_view kRequiredApexs[] = {
"com.android.art",
"com.android.runtime",
+ "com.android.sdkext", // For derive_classpath
};
std::array<bool, arraysize(kRequiredApexs)> found_apexs{ false, false };
DIR* apex_dir = opendir("/apex");
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index f67ab81..7082017 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -20,6 +20,7 @@
"libcutils",
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libinstalld",
"liblog",
@@ -44,6 +45,7 @@
"server_configurable_flags",
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libinstalld",
"liblog",
@@ -84,6 +86,7 @@
"server_configurable_flags",
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libinstalld",
"liblog",
@@ -124,6 +127,7 @@
"server_configurable_flags",
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libinstalld",
"liblog",
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index b429fb3..90db509 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -481,7 +481,12 @@
name.c_str());
std::thread([=] {
- (void)base::SetProperty("ctl.interface_start", "aidl/" + name);
+ if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) {
+ LOG(INFO) << "Tried to start aidl service " << name
+ << " as a lazy service, but was unable to. Usually this happens when a "
+ "service is not installed, but if the service is intended to be used as a "
+ "lazy service, then it may be configured incorrectly.";
+ }
}).detach();
}
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index f2302f7..ee5f508 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -19,6 +19,7 @@
#include <binder/RpcConnection.h>
#include <arpa/inet.h>
+#include <inttypes.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
@@ -45,9 +46,55 @@
namespace android {
+using base::borrowed_fd;
using base::unique_fd;
using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
+namespace {
+bool checkSockaddrSize(const char* name, size_t actual, size_t expected) {
+ if (actual >= expected) return true;
+ ALOGW("getSockaddrPort: family is %s but size is %zu < %zu", name, actual, expected);
+ return false;
+}
+
+// Get the port number of |storage| for certain families. Requires storage->sa_family to be
+// set to a known family; otherwise, return nullopt.
+std::optional<unsigned int> getSockaddrPort(const sockaddr* storage, socklen_t len) {
+ switch (storage->sa_family) {
+ case AF_INET: {
+ if (!checkSockaddrSize("INET", len, sizeof(sockaddr_in))) return std::nullopt;
+ auto inetStorage = reinterpret_cast<const sockaddr_in*>(storage);
+ return ntohs(inetStorage->sin_port);
+ }
+ default: {
+ uint16_t family = storage->sa_family;
+ ALOGW("Don't know how to infer port for family %" PRIu16, family);
+ return std::nullopt;
+ }
+ }
+}
+
+std::optional<unsigned int> getSocketPort(borrowed_fd socketfd,
+ const RpcConnection::SocketAddress& socketAddress) {
+ sockaddr_storage storage{};
+ socklen_t len = sizeof(storage);
+ auto storagePtr = reinterpret_cast<sockaddr*>(&storage);
+ if (0 != getsockname(socketfd.get(), storagePtr, &len)) {
+ int savedErrno = errno;
+ ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
+ strerror(savedErrno));
+ return std::nullopt;
+ }
+
+ // getsockname does not fill in family, but getSockaddrPort() needs it.
+ if (storage.ss_family == AF_UNSPEC) {
+ storage.ss_family = socketAddress.addr()->sa_family;
+ }
+ return getSockaddrPort(storagePtr, len);
+}
+
+} // namespace
+
RpcConnection::SocketAddress::~SocketAddress() {}
RpcConnection::RpcConnection() {
@@ -92,8 +139,8 @@
return setupSocketServer(UnixSocketAddress(path));
}
-bool RpcConnection::addUnixDomainClient(const char* path) {
- return addSocketClient(UnixSocketAddress(path));
+bool RpcConnection::setupUnixDomainClient(const char* path) {
+ return setupSocketClient(UnixSocketAddress(path));
}
#ifdef __BIONIC__
@@ -124,8 +171,8 @@
return setupSocketServer(VsockSocketAddress(kAnyCid, port));
}
-bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) {
- return addSocketClient(VsockSocketAddress(cid, port));
+bool RpcConnection::setupVsockClient(unsigned int cid, unsigned int port) {
+ return setupSocketClient(VsockSocketAddress(cid, port));
}
#endif // __BIONIC__
@@ -166,26 +213,39 @@
return AddrInfo(aiStart, &freeaddrinfo);
}
-bool RpcConnection::setupInetServer(unsigned int port) {
+bool RpcConnection::setupInetServer(unsigned int port, unsigned int* assignedPort) {
const char* kAddr = "127.0.0.1";
+ if (assignedPort != nullptr) *assignedPort = 0;
auto aiStart = GetAddrInfo(kAddr, port);
if (aiStart == nullptr) return false;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
- if (setupSocketServer(socketAddress)) return true;
+ if (!setupSocketServer(socketAddress)) {
+ continue;
+ }
+ auto realPort = getSocketPort(mServer.get(), socketAddress);
+ LOG_ALWAYS_FATAL_IF(!realPort.has_value(), "Unable to get port number after setting up %s",
+ socketAddress.toString().c_str());
+ LOG_ALWAYS_FATAL_IF(port != 0 && *realPort != port,
+ "Requesting inet server on %s but it is set up on %u.",
+ socketAddress.toString().c_str(), *realPort);
+ if (assignedPort != nullptr) {
+ *assignedPort = *realPort;
+ }
+ return true;
}
ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
port);
return false;
}
-bool RpcConnection::addInetClient(const char* addr, unsigned int port) {
+bool RpcConnection::setupInetClient(const char* addr, unsigned int port) {
auto aiStart = GetAddrInfo(addr, port);
if (aiStart == nullptr) return false;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
- if (addSocketClient(socketAddress)) return true;
+ if (setupSocketClient(socketAddress)) return true;
}
ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
return false;
@@ -208,6 +268,11 @@
return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this));
}
+status_t RpcConnection::getMaxThreads(size_t* maxThreads) {
+ ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
+ return state()->getMaxThreads(socket.fd(), sp<RpcConnection>::fromExisting(this), maxThreads);
+}
+
status_t RpcConnection::transact(const RpcAddress& address, uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this),
@@ -288,7 +353,39 @@
return true;
}
-bool RpcConnection::addSocketClient(const SocketAddress& addr) {
+bool RpcConnection::setupSocketClient(const SocketAddress& addr) {
+ {
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ LOG_ALWAYS_FATAL_IF(mClients.size() != 0,
+ "Must only setup connection once, but already has %zu clients",
+ mClients.size());
+ }
+
+ if (!setupOneSocketClient(addr)) return false;
+
+ // TODO(b/185167543): we should add additional connections dynamically
+ // instead of all at once.
+ // TODO(b/186470974): first risk of blocking
+ size_t numThreadsAvailable;
+ if (status_t status = getMaxThreads(&numThreadsAvailable); status != OK) {
+ ALOGE("Could not get max threads after initial connection to %s: %s",
+ addr.toString().c_str(), statusToString(status).c_str());
+ return false;
+ }
+
+ // we've already setup one client
+ for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
+ // TODO(b/185167543): avoid race w/ accept4 not being called on server
+ for (size_t tries = 0; tries < 5; tries++) {
+ if (setupOneSocketClient(addr)) break;
+ usleep(10000);
+ }
+ }
+
+ return true;
+}
+
+bool RpcConnection::setupOneSocketClient(const SocketAddress& addr) {
unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
if (serverFd == -1) {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 6dc4f95..8f2805f 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -19,6 +19,7 @@
#include <sys/socket.h>
#include <sys/un.h>
+#include <thread>
#include <vector>
#include <binder/Parcel.h>
@@ -30,8 +31,6 @@
namespace android {
-using base::unique_fd;
-
RpcServer::RpcServer() {}
RpcServer::~RpcServer() {}
@@ -43,16 +42,19 @@
mAgreedExperimental = true;
}
-sp<RpcConnection> RpcServer::addClientConnection() {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
-
- auto connection = RpcConnection::make();
- connection->setForServer(sp<RpcServer>::fromExisting(this));
+void RpcServer::setMaxThreads(size_t threads) {
+ LOG_ALWAYS_FATAL_IF(threads <= 0, "RpcServer is useless without threads");
{
+ // this lock should only ever be needed in the error case
std::lock_guard<std::mutex> _l(mLock);
- mConnections.push_back(connection);
+ LOG_ALWAYS_FATAL_IF(mConnections.size() > 0,
+ "Must specify max threads before creating a connection");
}
- return connection;
+ mMaxThreads = threads;
+}
+
+size_t RpcServer::getMaxThreads() {
+ return mMaxThreads;
}
void RpcServer::setRootObject(const sp<IBinder>& binder) {
@@ -65,4 +67,35 @@
return mRootObject;
}
+sp<RpcConnection> RpcServer::addClientConnection() {
+ LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+
+ auto connection = RpcConnection::make();
+ connection->setForServer(sp<RpcServer>::fromExisting(this));
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ LOG_ALWAYS_FATAL_IF(mStarted,
+ "currently only supports adding client connections at creation time");
+ mConnections.push_back(connection);
+ }
+ return connection;
+}
+
+void RpcServer::join() {
+ std::vector<std::thread> pool;
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ mStarted = true;
+ for (const sp<RpcConnection>& connection : mConnections) {
+ for (size_t i = 0; i < mMaxThreads; i++) {
+ pool.push_back(std::thread([=] { connection->join(); }));
+ }
+ }
+ }
+
+ // TODO(b/185167543): don't waste extra thread for join, and combine threads
+ // between clients
+ for (auto& t : pool) t.join();
+}
+
} // namespace android
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index d934136..6bfcc42 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -248,6 +248,31 @@
return reply.readStrongBinder();
}
+status_t RpcState::getMaxThreads(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+ size_t* maxThreads) {
+ Parcel data;
+ data.markForRpc(connection);
+ Parcel reply;
+
+ status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_MAX_THREADS, data,
+ connection, &reply, 0);
+ if (status != OK) {
+ ALOGE("Error getting max threads: %s", statusToString(status).c_str());
+ return status;
+ }
+
+ int32_t threads;
+ status = reply.readInt32(&threads);
+ if (status != OK) return status;
+ if (threads <= 0) {
+ ALOGE("Error invalid max threads: %d", threads);
+ return BAD_VALUE;
+ }
+
+ *maxThreads = threads;
+ return OK;
+}
+
status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address, uint32_t code,
const Parcel& data, const sp<RpcConnection>& connection, Parcel* reply,
uint32_t flags) {
@@ -516,23 +541,25 @@
replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
} else {
LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
- // special case for 'zero' address (special server commands)
- switch (transaction->code) {
- case RPC_SPECIAL_TRANSACT_GET_ROOT: {
- sp<IBinder> root;
- sp<RpcServer> server = connection->server().promote();
- if (server) {
- root = server->getRootObject();
- } else {
- ALOGE("Root object requested, but no server attached.");
- }
- replyStatus = reply.writeStrongBinder(root);
- break;
+ sp<RpcServer> server = connection->server().promote();
+ if (server) {
+ // special case for 'zero' address (special server commands)
+ switch (transaction->code) {
+ case RPC_SPECIAL_TRANSACT_GET_ROOT: {
+ replyStatus = reply.writeStrongBinder(server->getRootObject());
+ break;
+ }
+ case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
+ replyStatus = reply.writeInt32(server->getMaxThreads());
+ break;
+ }
+ default: {
+ replyStatus = UNKNOWN_TRANSACTION;
+ }
}
- default: {
- replyStatus = UNKNOWN_TRANSACTION;
- }
+ } else {
+ ALOGE("Special command sent, but no server object attached.");
}
}
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index f4f5151..1cfa406 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -51,6 +51,8 @@
~RpcState();
sp<IBinder> getRootObject(const base::unique_fd& fd, const sp<RpcConnection>& connection);
+ status_t getMaxThreads(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+ size_t* maxThreadsOut);
[[nodiscard]] status_t transact(const base::unique_fd& fd, const RpcAddress& address,
uint32_t code, const Parcel& data,
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 60ec6c9..cc7cacb 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -47,6 +47,7 @@
*/
enum : uint32_t {
RPC_SPECIAL_TRANSACT_GET_ROOT = 0,
+ RPC_SPECIAL_TRANSACT_GET_MAX_THREADS = 1,
};
// serialization is like:
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
index 2395e78..3a2d8e5 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -59,7 +59,7 @@
* This should be called once per thread, matching 'join' in the remote
* process.
*/
- [[nodiscard]] bool addUnixDomainClient(const char* path);
+ [[nodiscard]] bool setupUnixDomainClient(const char* path);
#ifdef __BIONIC__
/**
@@ -70,18 +70,24 @@
/**
* Connects to an RPC server at the CVD & port.
*/
- [[nodiscard]] bool addVsockClient(unsigned int cvd, unsigned int port);
+ [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
#endif // __BIONIC__
/**
- * Creates an RPC server at the current port.
+ * Creates an RPC server at the current port using IPv4.
+ *
+ * TODO(b/182914638): IPv6 support
+ *
+ * Set |port| to 0 to pick an ephemeral port; see discussion of
+ * /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort|
+ * will be set to the picked port number, if it is not null.
*/
- [[nodiscard]] bool setupInetServer(unsigned int port);
+ [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
/**
* Connects to an RPC server at the given address and port.
*/
- [[nodiscard]] bool addInetClient(const char* addr, unsigned int port);
+ [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
/**
* For debugging!
@@ -98,16 +104,16 @@
*/
sp<IBinder> getRootObject();
+ /**
+ * Query the other side of the connection for the maximum number of threads
+ * it supports (maximum number of concurrent non-nested synchronous transactions)
+ */
+ status_t getMaxThreads(size_t* maxThreads);
+
[[nodiscard]] status_t transact(const RpcAddress& address, uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
[[nodiscard]] status_t sendDecStrong(const RpcAddress& address);
- /**
- * Adds a server thread accepting connections. Must be called after
- * setup*Server.
- */
- void join();
-
~RpcConnection();
void setForServer(const wp<RpcServer>& server);
@@ -126,8 +132,11 @@
private:
friend sp<RpcConnection>;
+ friend RpcServer;
RpcConnection();
+ void join();
+
struct ConnectionSocket : public RefBase {
base::unique_fd fd;
@@ -137,7 +146,8 @@
};
bool setupSocketServer(const SocketAddress& address);
- bool addSocketClient(const SocketAddress& address);
+ bool setupSocketClient(const SocketAddress& address);
+ bool setupOneSocketClient(const SocketAddress& address);
void addClient(base::unique_fd&& fd);
sp<ConnectionSocket> assignServerToThisThread(base::unique_fd&& fd);
bool removeServerSocket(const sp<ConnectionSocket>& socket);
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index a665fad..9247128 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -40,6 +40,24 @@
void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
/**
+ * This must be called before adding a client connection.
+ *
+ * If this is not specified, this will be a single-threaded server.
+ *
+ * TODO(b/185167543): these are currently created per client, but these
+ * should be shared.
+ */
+ void setMaxThreads(size_t threads);
+ size_t getMaxThreads();
+
+ /**
+ * The root object can be retrieved by any client, without any
+ * authentication. TODO(b/183988761)
+ */
+ void setRootObject(const sp<IBinder>& binder);
+ sp<IBinder> getRootObject();
+
+ /**
* Setup a static connection, when the number of clients are known.
*
* Each call to this function corresponds to a different client, and clients
@@ -50,15 +68,9 @@
sp<RpcConnection> addClientConnection();
/**
- * The root object can be retrieved by any client, without any
- * authentication. TODO(b/183988761)
+ * You must have at least one client connection before calling this.
*/
- void setRootObject(const sp<IBinder>& binder);
-
- /**
- * Root object set with setRootObject
- */
- sp<IBinder> getRootObject();
+ void join();
~RpcServer();
@@ -67,8 +79,10 @@
RpcServer();
bool mAgreedExperimental = false;
+ bool mStarted = false; // TODO(b/185167543): support dynamically added clients
+ size_t mMaxThreads = 1;
- std::mutex mLock;
+ std::mutex mLock; // for below
sp<IBinder> mRootObject;
std::vector<sp<RpcConnection>> mConnections; // per-client
};
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 7c82226..b3282ff 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -127,12 +127,12 @@
sp<RpcConnection> connection = server->addClientConnection();
CHECK(connection->setupUnixDomainServer(addr.c_str()));
- connection->join();
+ server->join();
}).detach();
for (size_t tries = 0; tries < 5; tries++) {
usleep(10000);
- if (gConnection->addUnixDomainClient(addr.c_str())) goto success;
+ if (gConnection->setupUnixDomainClient(addr.c_str())) goto success;
}
LOG(FATAL) << "Could not connect.";
success:
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index dd68fdb..f3ec904 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -17,6 +17,7 @@
#include <BnBinderRpcSession.h>
#include <BnBinderRpcTest.h>
#include <aidl/IBinderRpcTest.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
#include <android/binder_libbinder.h>
@@ -176,14 +177,27 @@
};
sp<IBinder> MyBinderRpcTest::mHeldBinder;
+class Pipe {
+public:
+ Pipe() { CHECK(android::base::Pipe(&mRead, &mWrite)); }
+ Pipe(Pipe&&) = default;
+ android::base::borrowed_fd readEnd() { return mRead; }
+ android::base::borrowed_fd writeEnd() { return mWrite; }
+
+private:
+ android::base::unique_fd mRead;
+ android::base::unique_fd mWrite;
+};
+
class Process {
public:
- Process(const std::function<void()>& f) {
+ Process(Process&&) = default;
+ Process(const std::function<void(Pipe*)>& f) {
if (0 == (mPid = fork())) {
// racey: assume parent doesn't crash before this is set
prctl(PR_SET_PDEATHSIG, SIGHUP);
- f();
+ f(&mPipe);
}
}
~Process() {
@@ -191,9 +205,11 @@
kill(mPid, SIGKILL);
}
}
+ Pipe* getPipe() { return &mPipe; }
private:
pid_t mPid = 0;
+ Pipe mPipe;
};
static std::string allocateSocketAddress() {
@@ -215,6 +231,7 @@
// whether connection should be invalidated by end of run
bool expectInvalid = false;
+ ProcessConnection(ProcessConnection&&) = default;
~ProcessConnection() {
rootBinder = nullptr;
EXPECT_NE(nullptr, connection);
@@ -238,6 +255,7 @@
// pre-casted root object
sp<IBinderRpcTest> rootIface;
+ BinderRpcTestProcessConnection(BinderRpcTestProcessConnection&&) = default;
~BinderRpcTestProcessConnection() {
if (!proc.expectInvalid) {
int32_t remoteBinders = 0;
@@ -280,20 +298,19 @@
ProcessConnection createRpcTestSocketServerProcess(
size_t numThreads,
const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
- CHECK_GT(numThreads, 0);
-
SocketType socketType = GetParam();
std::string addr = allocateSocketAddress();
unlink(addr.c_str());
- static unsigned int port = 3456;
- port++;
+ static unsigned int vsockPort = 3456;
+ vsockPort++;
auto ret = ProcessConnection{
- .host = Process([&] {
+ .host = Process([&](Pipe* pipe) {
sp<RpcServer> server = RpcServer::make();
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ server->setMaxThreads(numThreads);
// server supporting one client on one socket
sp<RpcConnection> connection = server->addClientConnection();
@@ -304,53 +321,57 @@
break;
#ifdef __BIONIC__
case SocketType::VSOCK:
- CHECK(connection->setupVsockServer(port));
+ CHECK(connection->setupVsockServer(vsockPort));
break;
#endif // __BIONIC__
- case SocketType::INET:
- CHECK(connection->setupInetServer(port));
+ case SocketType::INET: {
+ unsigned int outPort = 0;
+ CHECK(connection->setupInetServer(0, &outPort));
+ CHECK_NE(0, outPort);
+ CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort,
+ sizeof(outPort)));
break;
+ }
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
configure(server, connection);
- // accept 'numThreads' connections
- std::vector<std::thread> pool;
- for (size_t i = 0; i + 1 < numThreads; i++) {
- pool.push_back(std::thread([=] { connection->join(); }));
- }
- connection->join();
- for (auto& t : pool) t.join();
+ server->join();
}),
.connection = RpcConnection::make(),
};
- // create remainder of connections
- for (size_t i = 0; i < numThreads; i++) {
- for (size_t tries = 0; tries < 5; tries++) {
- usleep(10000);
- switch (socketType) {
- case SocketType::UNIX:
- if (ret.connection->addUnixDomainClient(addr.c_str())) goto success;
- break;
-#ifdef __BIONIC__
- case SocketType::VSOCK:
- if (ret.connection->addVsockClient(VMADDR_CID_LOCAL, port)) goto success;
- break;
-#endif // __BIONIC__
- case SocketType::INET:
- if (ret.connection->addInetClient("127.0.0.1", port)) goto success;
- break;
- default:
- LOG_ALWAYS_FATAL("Unknown socket type");
- }
- }
- LOG_ALWAYS_FATAL("Could not connect");
- success:;
+ unsigned int inetPort = 0;
+ if (socketType == SocketType::INET) {
+ CHECK(android::base::ReadFully(ret.host.getPipe()->readEnd(), &inetPort,
+ sizeof(inetPort)));
+ CHECK_NE(0, inetPort);
}
+ // create remainder of connections
+ for (size_t tries = 0; tries < 10; tries++) {
+ usleep(10000);
+ switch (socketType) {
+ case SocketType::UNIX:
+ if (ret.connection->setupUnixDomainClient(addr.c_str())) goto success;
+ break;
+#ifdef __BIONIC__
+ case SocketType::VSOCK:
+ if (ret.connection->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
+ break;
+#endif // __BIONIC__
+ case SocketType::INET:
+ if (ret.connection->setupInetClient("127.0.0.1", inetPort)) goto success;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ }
+ }
+ LOG_ALWAYS_FATAL("Could not connect");
+ success:
+
ret.rootBinder = ret.connection->getRootObject();
return ret;
}
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 748f795..16ce15b 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -68,11 +68,9 @@
name: "gl_headers",
vendor_available: true,
export_include_dirs: ["include"],
-}
-
-llndk_headers {
- name: "gl_llndk_headers",
- export_include_dirs: ["include"],
+ llndk: {
+ llndk_headers: true,
+ },
}
subdirs = [
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 6d59ac0..daaaf88 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -144,7 +144,7 @@
defaults: ["egl_libs_defaults"],
llndk: {
symbol_file: "libEGL.map.txt",
- export_llndk_headers: ["gl_llndk_headers"],
+ export_llndk_headers: ["gl_headers"],
// Don't export EGL/include from the LLNDK variant.
override_export_include_dirs: [],
},
@@ -215,7 +215,7 @@
defaults: ["gles_libs_defaults"],
llndk: {
symbol_file: "libGLESv1_CM.map.txt",
- export_llndk_headers: ["gl_llndk_headers"],
+ export_llndk_headers: ["gl_headers"],
// Don't export EGL/include from the LLNDK variant.
override_export_include_dirs: [],
},
@@ -232,7 +232,7 @@
defaults: ["gles_libs_defaults"],
llndk: {
symbol_file: "libGLESv2.map.txt",
- export_llndk_headers: ["gl_llndk_headers"],
+ export_llndk_headers: ["gl_headers"],
// Don't export EGL/include from the LLNDK variant.
override_export_include_dirs: [],
},
@@ -252,7 +252,7 @@
defaults: ["gles_libs_defaults"],
llndk: {
symbol_file: "libGLESv3.map.txt",
- export_llndk_headers: ["gl_llndk_headers"],
+ export_llndk_headers: ["gl_headers"],
// Don't export EGL/include from the LLNDK variant.
override_export_include_dirs: [],
},
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index d4cb928..440c5b1 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -34,7 +34,7 @@
llndk: {
symbol_file: "libvulkan.map.txt",
export_llndk_headers: [
- "vulkan_headers_llndk",
+ "vulkan_headers",
],
},
clang: true,