Merge "0->nullptr."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index b8df99f..501e281 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1640,6 +1640,10 @@
MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
} else {
RunCommand("LSMOD", {"lsmod"});
+ RunCommand("MODULES INFO",
+ {"sh", "-c", "cat /proc/modules | cut -d' ' -f1 | "
+ " while read MOD ; do echo modinfo:$MOD ; modinfo $MOD ; "
+ "done"}, CommandOptions::AS_ROOT);
}
if (android::base::GetBoolProperty("ro.logd.kernel", false)) {
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index b503beb..6165911 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -123,16 +123,20 @@
std::string regStr = (reRegister) ? "Re-registering" : "Registering";
ALOGI("%s service %s", regStr.c_str(), name.c_str());
- if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) {
- ALOGE("Failed to register service %s", name.c_str());
+ if (Status status = manager->addService(name.c_str(), service, allowIsolated, dumpFlags);
+ !status.isOk()) {
+ ALOGE("Failed to register service %s (%s)", name.c_str(), status.toString8().c_str());
return false;
}
if (!reRegister) {
- if (!manager->registerClientCallback(name, service,
- sp<android::os::IClientCallback>::fromExisting(this))
- .isOk()) {
- ALOGE("Failed to add client callback for service %s", name.c_str());
+ if (Status status =
+ manager->registerClientCallback(name, service,
+ sp<android::os::IClientCallback>::fromExisting(
+ this));
+ !status.isOk()) {
+ ALOGE("Failed to add client callback for service %s (%s)", name.c_str(),
+ status.toString8().c_str());
return false;
}
@@ -171,10 +175,10 @@
auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
for (auto& [name, entry] : mRegisteredServices) {
- bool success = manager->tryUnregisterService(name, entry.service).isOk();
+ Status status = manager->tryUnregisterService(name, entry.service);
- if (!success) {
- ALOGI("Failed to unregister service %s", name.c_str());
+ if (!status.isOk()) {
+ ALOGI("Failed to unregister service %s (%s)", name.c_str(), status.toString8().c_str());
return false;
}
entry.registered = false;
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 7da6847..e9186f0 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -216,4 +216,16 @@
return true;
}
+void RpcServer::onSessionTerminating(const sp<RpcSession>& session) {
+ auto id = session->mId;
+ LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
+ LOG_RPC_DETAIL("Dropping session %d", *id);
+
+ std::lock_guard<std::mutex> _l(mLock);
+ auto it = mSessions.find(*id);
+ LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %d", *id);
+ LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %d", *id);
+ (void)mSessions.erase(it);
+}
+
} // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 09ec20d..d9b5c73 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -24,6 +24,7 @@
#include <string_view>
#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
#include <binder/Stability.h>
#include <utils/String8.h>
@@ -48,7 +49,7 @@
LOG_RPC_DETAIL("RpcSession destroyed %p", this);
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mServers.size() != 0,
+ LOG_ALWAYS_FATAL_IF(mServerConnections.size() != 0,
"Should not be able to destroy a session with servers in use.");
}
@@ -142,8 +143,10 @@
holdThis->join(unique_fd(fd));
{
std::lock_guard<std::mutex> _l(holdThis->mMutex);
- size_t erased = mThreads.erase(std::this_thread::get_id());
- LOG_ALWAYS_FATAL_IF(erased != 0, "Could not erase thread.");
+ auto it = mThreads.find(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(it == mThreads.end());
+ it->second.detach();
+ mThreads.erase(it);
}
});
mThreads[thread.get_id()] = std::move(thread);
@@ -168,6 +171,22 @@
"bad state: connection object guaranteed to be in list");
}
+void RpcSession::terminateLocked() {
+ // TODO(b/185167543):
+ // - kindly notify other side of the connection of termination (can't be
+ // locked)
+ // - prevent new client/servers from being added
+ // - stop all threads which are currently reading/writing
+ // - terminate RpcState?
+
+ if (mTerminated) return;
+
+ sp<RpcServer> server = mForServer.promote();
+ if (server) {
+ server->onSessionTerminating(sp<RpcSession>::fromExisting(this));
+ }
+}
+
wp<RpcServer> RpcSession::server() {
return mForServer;
}
@@ -175,9 +194,9 @@
bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
{
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mClients.size() != 0,
+ LOG_ALWAYS_FATAL_IF(mClientConnections.size() != 0,
"Must only setup session once, but already has %zu clients",
- mClients.size());
+ mClientConnections.size());
}
if (!setupOneSocketClient(addr, RPC_SESSION_ID_NEW)) return false;
@@ -242,7 +261,7 @@
std::lock_guard<std::mutex> _l(mMutex);
sp<RpcConnection> session = sp<RpcConnection>::make();
session->fd = std::move(fd);
- mClients.push_back(session);
+ mClientConnections.push_back(session);
}
void RpcSession::setForServer(const wp<RpcServer>& server, int32_t sessionId) {
@@ -255,15 +274,19 @@
sp<RpcConnection> session = sp<RpcConnection>::make();
session->fd = std::move(fd);
session->exclusiveTid = gettid();
- mServers.push_back(session);
+ mServerConnections.push_back(session);
return session;
}
bool RpcSession::removeServerConnection(const sp<RpcConnection>& connection) {
std::lock_guard<std::mutex> _l(mMutex);
- if (auto it = std::find(mServers.begin(), mServers.end(), connection); it != mServers.end()) {
- mServers.erase(it);
+ if (auto it = std::find(mServerConnections.begin(), mServerConnections.end(), connection);
+ it != mServerConnections.end()) {
+ mServerConnections.erase(it);
+ if (mServerConnections.size() == 0) {
+ terminateLocked();
+ }
return true;
}
return false;
@@ -283,10 +306,11 @@
// CHECK FOR DEDICATED CLIENT SOCKET
//
// A server/looper should always use a dedicated session if available
- findConnection(tid, &exclusive, &available, mSession->mClients, mSession->mClientsOffset);
+ findConnection(tid, &exclusive, &available, mSession->mClientConnections,
+ mSession->mClientConnectionsOffset);
// WARNING: this assumes a server cannot request its client to send
- // a transaction, as mServers is excluded below.
+ // a transaction, as mServerConnections is excluded below.
//
// Imagine we have more than one thread in play, and a single thread
// sends a synchronous, then an asynchronous command. Imagine the
@@ -296,7 +320,8 @@
// command. So, we move to considering the second available thread
// for subsequent calls.
if (use == ConnectionUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
- mSession->mClientsOffset = (mSession->mClientsOffset + 1) % mSession->mClients.size();
+ mSession->mClientConnectionsOffset =
+ (mSession->mClientConnectionsOffset + 1) % mSession->mClientConnections.size();
}
// USE SERVING SOCKET (for nested transaction)
@@ -304,7 +329,7 @@
// asynchronous calls cannot be nested
if (use != ConnectionUse::CLIENT_ASYNC) {
// server connections are always assigned to a thread
- findConnection(tid, &exclusive, nullptr /*available*/, mSession->mServers,
+ findConnection(tid, &exclusive, nullptr /*available*/, mSession->mServerConnections,
0 /* index hint */);
}
@@ -320,13 +345,13 @@
}
// in regular binder, this would usually be a deadlock :)
- LOG_ALWAYS_FATAL_IF(mSession->mClients.size() == 0,
+ LOG_ALWAYS_FATAL_IF(mSession->mClientConnections.size() == 0,
"Not a client of any session. You must create a session to an "
"RPC server to make any non-nested (e.g. oneway or on another thread) "
"calls.");
LOG_RPC_DETAIL("No available session (have %zu clients and %zu servers). Waiting...",
- mSession->mClients.size(), mSession->mServers.size());
+ mSession->mClientConnections.size(), mSession->mServerConnections.size());
mSession->mAvailableConnectionCv.wait(_l);
}
mSession->mWaitingThreads--;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 96190dc..20fdbfe 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -326,7 +326,11 @@
.asyncNumber = asyncNumber,
};
- std::vector<uint8_t> transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+ ByteVec transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+ if (!transactionData.valid()) {
+ return NO_MEMORY;
+ }
+
memcpy(transactionData.data() + 0, &transaction, sizeof(RpcWireTransaction));
memcpy(transactionData.data() + sizeof(RpcWireTransaction), data.data(), data.dataSize());
@@ -379,9 +383,12 @@
if (status != OK) return status;
}
- uint8_t* data = new uint8_t[command.bodySize];
+ ByteVec data(command.bodySize);
+ if (!data.valid()) {
+ return NO_MEMORY;
+ }
- if (!rpcRec(fd, "reply body", data, command.bodySize)) {
+ if (!rpcRec(fd, "reply body", data.data(), command.bodySize)) {
return DEAD_OBJECT;
}
@@ -391,9 +398,10 @@
terminate();
return BAD_VALUE;
}
- RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data);
+ RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data.data());
if (rpcReply->status != OK) return rpcReply->status;
+ data.release();
reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data),
nullptr, 0, cleanup_reply_data);
@@ -461,7 +469,10 @@
const RpcWireHeader& command) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
- std::vector<uint8_t> transactionData(command.bodySize);
+ ByteVec transactionData(command.bodySize);
+ if (!transactionData.valid()) {
+ return NO_MEMORY;
+ }
if (!rpcRec(fd, "transaction body", transactionData.data(), transactionData.size())) {
return DEAD_OBJECT;
}
@@ -479,7 +490,7 @@
}
status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<RpcSession>& session,
- std::vector<uint8_t>&& transactionData) {
+ ByteVec transactionData) {
if (transactionData.size() < sizeof(RpcWireTransaction)) {
ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!",
sizeof(RpcWireTransaction), transactionData.size());
@@ -500,7 +511,6 @@
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
ALOGE("Unknown binder address %s.", addr.toString().c_str());
- dump();
replyStatus = BAD_VALUE;
} else {
target = it->second.binder.promote();
@@ -630,7 +640,7 @@
// justification for const_cast (consider avoiding priority_queue):
// - AsyncTodo operator< doesn't depend on 'data' object
// - gotta go fast
- std::vector<uint8_t> data = std::move(
+ ByteVec data = std::move(
const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data);
it->second.asyncTodo.pop();
_l.unlock();
@@ -644,7 +654,10 @@
.status = replyStatus,
};
- std::vector<uint8_t> replyData(sizeof(RpcWireReply) + reply.dataSize());
+ ByteVec replyData(sizeof(RpcWireReply) + reply.dataSize());
+ if (!replyData.valid()) {
+ return NO_MEMORY;
+ }
memcpy(replyData.data() + 0, &rpcReply, sizeof(RpcWireReply));
memcpy(replyData.data() + sizeof(RpcWireReply), reply.data(), reply.dataSize());
@@ -671,7 +684,10 @@
status_t RpcState::processDecStrong(const base::unique_fd& fd, const RpcWireHeader& command) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
- std::vector<uint8_t> commandData(command.bodySize);
+ ByteVec commandData(command.bodySize);
+ if (!commandData.valid()) {
+ return NO_MEMORY;
+ }
if (!rpcRec(fd, "dec ref body", commandData.data(), commandData.size())) {
return DEAD_OBJECT;
}
@@ -690,7 +706,6 @@
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
ALOGE("Unknown binder address %s for dec strong.", addr.toString().c_str());
- dump();
return OK;
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 3f3eb1c..83d0344 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -21,6 +21,7 @@
#include <binder/RpcSession.h>
#include <map>
+#include <optional>
#include <queue>
namespace android {
@@ -100,6 +101,20 @@
*/
void terminate();
+ // alternative to std::vector<uint8_t> that doesn't abort on too big of allocations
+ struct ByteVec {
+ explicit ByteVec(size_t size)
+ : mData(size > 0 ? new (std::nothrow) uint8_t[size] : nullptr), mSize(size) {}
+ bool valid() { return mSize == 0 || mData != nullptr; }
+ size_t size() { return mSize; }
+ uint8_t* data() { return mData.get(); }
+ uint8_t* release() { return mData.release(); }
+
+ private:
+ std::unique_ptr<uint8_t[]> mData;
+ size_t mSize;
+ };
+
[[nodiscard]] bool rpcSend(const base::unique_fd& fd, const char* what, const void* data,
size_t size);
[[nodiscard]] bool rpcRec(const base::unique_fd& fd, const char* what, void* data, size_t size);
@@ -113,7 +128,7 @@
const RpcWireHeader& command);
[[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd,
const sp<RpcSession>& session,
- std::vector<uint8_t>&& transactionData);
+ ByteVec transactionData);
[[nodiscard]] status_t processDecStrong(const base::unique_fd& fd,
const RpcWireHeader& command);
@@ -148,7 +163,7 @@
// async transaction queue, _only_ for local binder
struct AsyncTodo {
- std::vector<uint8_t> data; // most convenient format, to move it here
+ ByteVec data;
uint64_t asyncNumber = 0;
bool operator<(const AsyncTodo& o) const {
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index c98151d..8c9ba00 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -109,6 +109,10 @@
~RpcServer();
+ // internal use only
+
+ void onSessionTerminating(const sp<RpcSession>& session);
+
private:
friend sp<RpcServer>;
RpcServer();
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 3f58b2c..f647c95 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -118,6 +118,7 @@
void startThread(base::unique_fd client);
void join(base::unique_fd client);
+ void terminateLocked();
struct RpcConnection : public RefBase {
base::unique_fd fd;
@@ -162,13 +163,13 @@
bool mReentrant = false;
};
- // On the other side of a session, for each of mClients here, there should
- // be one of mServers on the other side (and vice versa).
+ // On the other side of a session, for each of mClientConnections here, there should
+ // be one of mServerConnections on the other side (and vice versa).
//
// For the simplest session, a single server with one client, you would
// have:
- // - the server has a single 'mServers' and a thread listening on this
- // - the client has a single 'mClients' and makes calls to this
+ // - the server has a single 'mServerConnections' and a thread listening on this
+ // - the client has a single 'mClientConnections' and makes calls to this
// - here, when the client makes a call, the server can call back into it
// (nested calls), but outside of this, the client will only ever read
// calls from the server when it makes a call itself.
@@ -187,15 +188,17 @@
std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
size_t mWaitingThreads = 0;
- size_t mClientsOffset = 0; // hint index into clients, ++ when sending an async transaction
- std::vector<sp<RpcConnection>> mClients;
- std::vector<sp<RpcConnection>> mServers;
+ // hint index into clients, ++ when sending an async transaction
+ size_t mClientConnectionsOffset = 0;
+ std::vector<sp<RpcConnection>> mClientConnections;
+ std::vector<sp<RpcConnection>> mServerConnections;
// TODO(b/185167543): use for reverse sessions (allow client to also
// serve calls on a session).
// TODO(b/185167543): allow sharing between different sessions in a
- // process? (or combine with mServers)
+ // process? (or combine with mServerConnections)
std::map<std::thread::id, std::thread> mThreads;
+ bool mTerminated = false;
};
} // namespace android