Merge "Updates OWNERS files"
diff --git a/cmds/bugreport/OWNERS b/cmds/bugreport/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/bugreport/OWNERS
+++ b/cmds/bugreport/OWNERS
@@ -1,4 +1,5 @@
set noparent
+gavincorkery@google.com
nandana@google.com
jsharkey@android.com
diff --git a/cmds/bugreportz/OWNERS b/cmds/bugreportz/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/bugreportz/OWNERS
+++ b/cmds/bugreportz/OWNERS
@@ -1,4 +1,5 @@
set noparent
+gavincorkery@google.com
nandana@google.com
jsharkey@android.com
diff --git a/cmds/dumpstate/OWNERS b/cmds/dumpstate/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/dumpstate/OWNERS
+++ b/cmds/dumpstate/OWNERS
@@ -1,4 +1,5 @@
set noparent
+gavincorkery@google.com
nandana@google.com
jsharkey@android.com
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 501e281..95c4923 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1963,6 +1963,8 @@
RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
+ RunDumpsys("DUMPSYS", {"vcn_management"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
if (include_sensitive_info) {
// Carrier apps' services will be dumped below in dumpsys activity service all-non-platform.
RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 4f6a89e..97a63ca 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -1,5 +1,6 @@
set noparent
+gavincorkery@google.com
nandana@google.com
jsharkey@android.com
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index c0cdcd6..dc10d1c 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -22,6 +22,7 @@
#include <thread>
#include <vector>
+#include <android-base/scopeguard.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
#include <log/log.h>
@@ -32,6 +33,7 @@
namespace android {
+using base::ScopeGuard;
using base::unique_fd;
RpcServer::RpcServer() {}
@@ -107,65 +109,51 @@
void RpcServer::setRootObject(const sp<IBinder>& binder) {
std::lock_guard<std::mutex> _l(mLock);
- mRootObject = binder;
+ mRootObjectWeak = mRootObject = binder;
+}
+
+void RpcServer::setRootObjectWeak(const wp<IBinder>& binder) {
+ std::lock_guard<std::mutex> _l(mLock);
+ mRootObject.clear();
+ mRootObjectWeak = binder;
}
sp<IBinder> RpcServer::getRootObject() {
std::lock_guard<std::mutex> _l(mLock);
- return mRootObject;
+ bool hasWeak = mRootObjectWeak.unsafe_get();
+ sp<IBinder> ret = mRootObjectWeak.promote();
+ ALOGW_IF(hasWeak && ret == nullptr, "RpcServer root object is freed, returning nullptr");
+ return ret;
}
void RpcServer::join() {
+ while (true) {
+ (void)acceptOne();
+ }
+}
+
+bool RpcServer::acceptOne() {
LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+ LOG_ALWAYS_FATAL_IF(!hasServer(), "RpcServer must be setup to join.");
+
+ unique_fd clientFd(
+ TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC)));
+
+ if (clientFd < 0) {
+ ALOGE("Could not accept4 socket: %s", strerror(errno));
+ return false;
+ }
+ LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
{
std::lock_guard<std::mutex> _l(mLock);
- LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join.");
+ std::thread thread =
+ std::thread(&RpcServer::establishConnection, this,
+ std::move(sp<RpcServer>::fromExisting(this)), std::move(clientFd));
+ mConnectingThreads[thread.get_id()] = std::move(thread);
}
- while (true) {
- unique_fd clientFd(TEMP_FAILURE_RETRY(
- accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC)));
-
- if (clientFd < 0) {
- ALOGE("Could not accept4 socket: %s", strerror(errno));
- continue;
- }
- LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
-
- // TODO(b/183988761): cannot trust this simple ID, should not block this
- // thread
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
- int32_t id;
- if (sizeof(id) != read(clientFd.get(), &id, sizeof(id))) {
- ALOGE("Could not read ID from fd %d", clientFd.get());
- continue;
- }
-
- {
- std::lock_guard<std::mutex> _l(mLock);
-
- sp<RpcSession> session;
- if (id == RPC_SESSION_ID_NEW) {
- // new client!
- LOG_ALWAYS_FATAL_IF(mSessionIdCounter >= INT32_MAX, "Out of session IDs");
- mSessionIdCounter++;
-
- session = RpcSession::make();
- session->setForServer(wp<RpcServer>::fromExisting(this), mSessionIdCounter);
-
- mSessions[mSessionIdCounter] = session;
- } else {
- auto it = mSessions.find(id);
- if (it == mSessions.end()) {
- ALOGE("Cannot add thread, no record of session with ID %d", id);
- continue;
- }
- session = it->second;
- }
-
- session->startThread(std::move(clientFd));
- }
- }
+ return true;
}
std::vector<sp<RpcSession>> RpcServer::listSessions() {
@@ -178,14 +166,74 @@
return sessions;
}
-bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
- LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
+size_t RpcServer::numUninitializedSessions() {
+ std::lock_guard<std::mutex> _l(mLock);
+ return mConnectingThreads.size();
+}
+void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd) {
+ LOG_ALWAYS_FATAL_IF(this != server.get(), "Must pass same ownership object");
+
+ // TODO(b/183988761): cannot trust this simple ID
+ LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+ bool idValid = true;
+ int32_t id;
+ if (sizeof(id) != read(clientFd.get(), &id, sizeof(id))) {
+ ALOGE("Could not read ID from fd %d", clientFd.get());
+ idValid = false;
+ }
+
+ std::thread thisThread;
+ sp<RpcSession> session;
{
std::lock_guard<std::mutex> _l(mLock);
- LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcServer can only have one server.");
+
+ auto threadId = mConnectingThreads.find(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(threadId == mConnectingThreads.end(),
+ "Must establish connection on owned thread");
+ thisThread = std::move(threadId->second);
+ ScopeGuard detachGuard = [&]() { thisThread.detach(); };
+ mConnectingThreads.erase(threadId);
+
+ if (!idValid) {
+ return;
+ }
+
+ if (id == RPC_SESSION_ID_NEW) {
+ LOG_ALWAYS_FATAL_IF(mSessionIdCounter >= INT32_MAX, "Out of session IDs");
+ mSessionIdCounter++;
+
+ session = RpcSession::make();
+ session->setForServer(wp<RpcServer>::fromExisting(this), mSessionIdCounter);
+
+ mSessions[mSessionIdCounter] = session;
+ } else {
+ auto it = mSessions.find(id);
+ if (it == mSessions.end()) {
+ ALOGE("Cannot add thread, no record of session with ID %d", id);
+ return;
+ }
+ session = it->second;
+ }
+
+ detachGuard.Disable();
+ session->preJoin(std::move(thisThread));
}
+ // avoid strong cycle
+ server = nullptr;
+ //
+ //
+ // DO NOT ACCESS MEMBER VARIABLES BELOW
+ //
+
+ session->join(std::move(clientFd));
+}
+
+bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
+ LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
+ LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
+
unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
if (serverFd == -1) {
@@ -223,4 +271,9 @@
(void)mSessions.erase(it);
}
+bool RpcServer::hasServer() {
+ std::lock_guard<std::mutex> _l(mLock);
+ return mServer.ok();
+}
+
} // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 0471705..05fa49e 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -84,7 +84,7 @@
return false;
}
- addClient(std::move(serverFd));
+ addClientConnection(std::move(serverFd));
return true;
}
@@ -93,7 +93,7 @@
return state()->getRootObject(connection.fd(), sp<RpcSession>::fromExisting(this));
}
-status_t RpcSession::getMaxThreads(size_t* maxThreads) {
+status_t RpcSession::getRemoteMaxThreads(size_t* maxThreads) {
ExclusiveConnection connection(sp<RpcSession>::fromExisting(this), ConnectionUse::CLIENT);
return state()->getMaxThreads(connection.fd(), sp<RpcSession>::fromExisting(this), maxThreads);
}
@@ -131,21 +131,13 @@
return OK;
}
-void RpcSession::startThread(unique_fd client) {
- std::lock_guard<std::mutex> _l(mMutex);
- sp<RpcSession> holdThis = sp<RpcSession>::fromExisting(this);
- int fd = client.release();
- auto thread = std::thread([=] {
- holdThis->join(unique_fd(fd));
- {
- std::lock_guard<std::mutex> _l(holdThis->mMutex);
- 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);
+void RpcSession::preJoin(std::thread thread) {
+ LOG_ALWAYS_FATAL_IF(thread.get_id() != std::this_thread::get_id(), "Must own this thread");
+
+ {
+ std::lock_guard<std::mutex> _l(mMutex);
+ mThreads[thread.get_id()] = std::move(thread);
+ }
}
void RpcSession::join(unique_fd client) {
@@ -165,6 +157,14 @@
LOG_ALWAYS_FATAL_IF(!removeServerConnection(connection),
"bad state: connection object guaranteed to be in list");
+
+ {
+ std::lock_guard<std::mutex> _l(mMutex);
+ auto it = mThreads.find(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(it == mThreads.end());
+ it->second.detach();
+ mThreads.erase(it);
+ }
}
void RpcSession::terminateLocked() {
@@ -201,7 +201,7 @@
// instead of all at once.
// TODO(b/186470974): first risk of blocking
size_t numThreadsAvailable;
- if (status_t status = getMaxThreads(&numThreadsAvailable); status != OK) {
+ if (status_t status = getRemoteMaxThreads(&numThreadsAvailable); status != OK) {
ALOGE("Could not get max threads after initial session to %s: %s", addr.toString().c_str(),
statusToString(status).c_str());
return false;
@@ -255,7 +255,7 @@
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
- addClient(std::move(serverFd));
+ addClientConnection(std::move(serverFd));
return true;
}
@@ -263,7 +263,7 @@
return false;
}
-void RpcSession::addClient(unique_fd fd) {
+void RpcSession::addClientConnection(unique_fd fd) {
std::lock_guard<std::mutex> _l(mMutex);
sp<RpcConnection> session = sp<RpcConnection>::make();
session->fd = std::move(fd);
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 20fdbfe..2ba9fa2 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -182,6 +182,27 @@
}
}
+RpcState::CommandData::CommandData(size_t size) : mSize(size) {
+ // The maximum size for regular binder is 1MB for all concurrent
+ // transactions. A very small proportion of transactions are even
+ // larger than a page, but we need to avoid allocating too much
+ // data on behalf of an arbitrary client, or we could risk being in
+ // a position where a single additional allocation could run out of
+ // memory.
+ //
+ // Note, this limit may not reflect the total amount of data allocated for a
+ // transaction (in some cases, additional fixed size amounts are added),
+ // though for rough consistency, we should avoid cases where this data type
+ // is used for multiple dynamic allocations for a single transaction.
+ constexpr size_t kMaxTransactionAllocation = 100 * 1000;
+ if (size == 0) return;
+ if (size > kMaxTransactionAllocation) {
+ ALOGW("Transaction requested too much data allocation %zu", size);
+ return;
+ }
+ mData.reset(new (std::nothrow) uint8_t[size]);
+}
+
bool RpcState::rpcSend(const base::unique_fd& fd, const char* what, const void* data, size_t size) {
LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, fd.get(), hexString(data, size).c_str());
@@ -326,7 +347,7 @@
.asyncNumber = asyncNumber,
};
- ByteVec transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+ CommandData transactionData(sizeof(RpcWireTransaction) + data.dataSize());
if (!transactionData.valid()) {
return NO_MEMORY;
}
@@ -383,7 +404,7 @@
if (status != OK) return status;
}
- ByteVec data(command.bodySize);
+ CommandData data(command.bodySize);
if (!data.valid()) {
return NO_MEMORY;
}
@@ -469,7 +490,7 @@
const RpcWireHeader& command) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
- ByteVec transactionData(command.bodySize);
+ CommandData transactionData(command.bodySize);
if (!transactionData.valid()) {
return NO_MEMORY;
}
@@ -490,7 +511,7 @@
}
status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<RpcSession>& session,
- ByteVec transactionData) {
+ CommandData transactionData) {
if (transactionData.size() < sizeof(RpcWireTransaction)) {
ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!",
sizeof(RpcWireTransaction), transactionData.size());
@@ -640,7 +661,7 @@
// justification for const_cast (consider avoiding priority_queue):
// - AsyncTodo operator< doesn't depend on 'data' object
// - gotta go fast
- ByteVec data = std::move(
+ CommandData data = std::move(
const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data);
it->second.asyncTodo.pop();
_l.unlock();
@@ -654,7 +675,7 @@
.status = replyStatus,
};
- ByteVec replyData(sizeof(RpcWireReply) + reply.dataSize());
+ CommandData replyData(sizeof(RpcWireReply) + reply.dataSize());
if (!replyData.valid()) {
return NO_MEMORY;
}
@@ -684,7 +705,7 @@
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);
- ByteVec commandData(command.bodySize);
+ CommandData commandData(command.bodySize);
if (!commandData.valid()) {
return NO_MEMORY;
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 83d0344..31f8a22 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -101,10 +101,10 @@
*/
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) {}
+ // Alternative to std::vector<uint8_t> that doesn't abort on allocation failure and caps
+ // large allocations to avoid being requested from allocating too much data.
+ struct CommandData {
+ explicit CommandData(size_t size);
bool valid() { return mSize == 0 || mData != nullptr; }
size_t size() { return mSize; }
uint8_t* data() { return mData.get(); }
@@ -128,7 +128,7 @@
const RpcWireHeader& command);
[[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd,
const sp<RpcSession>& session,
- ByteVec transactionData);
+ CommandData transactionData);
[[nodiscard]] status_t processDecStrong(const base::unique_fd& fd,
const RpcWireHeader& command);
@@ -163,7 +163,7 @@
// async transaction queue, _only_ for local binder
struct AsyncTodo {
- ByteVec data;
+ CommandData data;
uint64_t asyncNumber = 0;
bool operator<(const AsyncTodo& o) const {
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index 9659732..f3ba830 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -50,8 +50,12 @@
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
/**
* Force the service to persist, even when it has 0 clients.
- * If setting this flag from the server side, make sure to do so before calling registerService,
- * or there may be a race with the default dynamic shutdown.
+ * If setting this flag from the server side, make sure to do so before calling
+ * registerService, or there may be a race with the default dynamic shutdown.
+ *
+ * This should only be used if it is every eventually set to false. If a
+ * service needs to persist but doesn't need to dynamically shut down,
+ * prefer to control it with another mechanism such as ctl.start.
*/
void forcePersist(bool persist);
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 3534d51..771bbe6 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -22,6 +22,7 @@
#include <utils/RefBase.h>
#include <mutex>
+#include <thread>
// WARNING: This is a feature which is still in development, and it is subject
// to radical change. Any production use of this may subject your code to any
@@ -73,6 +74,11 @@
*/
[[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
+ /**
+ * If setup*Server has been successful, return true. Otherwise return false.
+ */
+ [[nodiscard]] bool hasServer();
+
void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
/**
@@ -89,8 +95,14 @@
/**
* The root object can be retrieved by any client, without any
* authentication. TODO(b/183988761)
+ *
+ * Holds a strong reference to the root object.
*/
void setRootObject(const sp<IBinder>& binder);
+ /**
+ * Holds a weak reference to the root object.
+ */
+ void setRootObjectWeak(const wp<IBinder>& binder);
sp<IBinder> getRootObject();
/**
@@ -101,9 +113,16 @@
void join();
/**
+ * Accept one connection on this server. You must have at least one client
+ * session before calling this.
+ */
+ [[nodiscard]] bool acceptOne();
+
+ /**
* For debugging!
*/
std::vector<sp<RpcSession>> listSessions();
+ size_t numUninitializedSessions();
~RpcServer();
@@ -115,6 +134,7 @@
friend sp<RpcServer>;
RpcServer();
+ void establishConnection(sp<RpcServer>&& session, base::unique_fd clientFd);
bool setupSocketServer(const RpcSocketAddress& address);
bool mAgreedExperimental = false;
@@ -123,7 +143,9 @@
base::unique_fd mServer; // socket we are accepting sessions on
std::mutex mLock; // for below
+ std::map<std::thread::id, std::thread> mConnectingThreads;
sp<IBinder> mRootObject;
+ wp<IBinder> mRootObjectWeak;
std::map<int32_t, sp<RpcSession>> mSessions;
int32_t mSessionIdCounter = 0;
};
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 0b77787..bcc213c 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -81,7 +81,7 @@
* Query the other side of the session for the maximum number of threads
* it supports (maximum number of concurrent non-nested synchronous transactions)
*/
- status_t getMaxThreads(size_t* maxThreads);
+ status_t getRemoteMaxThreads(size_t* maxThreads);
[[nodiscard]] status_t transact(const RpcAddress& address, uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -114,7 +114,9 @@
status_t readId();
- void startThread(base::unique_fd client);
+ // transfer ownership of thread
+ void preJoin(std::thread thread);
+ // join on thread passed to preJoin
void join(base::unique_fd client);
void terminateLocked();
@@ -128,7 +130,7 @@
bool setupSocketClient(const RpcSocketAddress& address);
bool setupOneSocketClient(const RpcSocketAddress& address, int32_t sessionId);
- void addClient(base::unique_fd fd);
+ void addClientConnection(base::unique_fd fd);
void setForServer(const wp<RpcServer>& server, int32_t sessionId);
sp<RpcConnection> assignServerToThisThread(base::unique_fd fd);
bool removeServerConnection(const sp<RpcConnection>& connection);
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index a90b4aa..2a66941 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -35,7 +35,7 @@
* \return EX_NONE on success.
*/
__attribute__((warn_unused_result)) binder_exception_t AServiceManager_addService(
- AIBinder* binder, const char* instance);
+ AIBinder* binder, const char* instance) __INTRODUCED_IN(29);
/**
* Gets a binder object with this specific instance name. Will return nullptr immediately if the
@@ -47,7 +47,8 @@
*
* \param instance identifier of the service used to lookup the service.
*/
-__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance)
+ __INTRODUCED_IN(29);
/**
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
@@ -59,7 +60,8 @@
*
* \param instance identifier of the service used to lookup the service.
*/
-__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
+ __INTRODUCED_IN(29);
/**
* Registers a lazy service with the default service manager under the 'instance' name.
@@ -135,6 +137,10 @@
/**
* Prevent lazy services without client from shutting down their process
*
+ * This should only be used if it is every eventually set to false. If a
+ * service needs to persist but doesn't need to dynamically shut down,
+ * prefer to control it with another mechanism.
+ *
* \param persist 'true' if the process should not exit.
*/
void AServiceManager_forceLazyServicesPersist(bool persist) __INTRODUCED_IN(31);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index c0f7c99..ec231b2 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -63,6 +63,9 @@
"libbinder",
"libutils",
],
+ static_libs: [
+ "libgmock",
+ ],
compile_multilib: "32",
multilib: { lib32: { suffix: "" } },
cflags: ["-DBINDER_IPC_32BIT=1"],
@@ -101,6 +104,9 @@
"libbinder",
"libutils",
],
+ static_libs: [
+ "libgmock",
+ ],
test_suites: ["device-tests", "vts"],
require_root: true,
}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 5676bd1..0c3fbcd 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <thread>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <binder/Binder.h>
@@ -41,6 +42,13 @@
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
using namespace android;
+using testing::Not;
+
+// e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message";
+MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) {
+ *result_listener << statusToString(arg);
+ return expected == arg;
+}
static ::testing::AssertionResult IsPageAligned(void *buf) {
if (((unsigned long)buf & ((unsigned long)PAGE_SIZE - 1)) == 0)
@@ -205,19 +213,16 @@
protected:
sp<IBinder> addServerEtc(int32_t *idPtr, int code)
{
- int ret;
int32_t id;
Parcel data, reply;
sp<IBinder> binder;
- ret = m_server->transact(code, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(code, data, &reply), StatusEq(NO_ERROR));
EXPECT_FALSE(binder != nullptr);
binder = reply.readStrongBinder();
EXPECT_TRUE(binder != nullptr);
- ret = reply.readInt32(&id);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
if (idPtr)
*idPtr = id;
return binder;
@@ -401,29 +406,25 @@
};
TEST_F(BinderLibTest, NopTransaction) {
- status_t ret;
Parcel data, reply;
- ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
}
TEST_F(BinderLibTest, NopTransactionOneway) {
- status_t ret;
Parcel data, reply;
- ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_ONE_WAY);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_ONE_WAY),
+ StatusEq(NO_ERROR));
}
TEST_F(BinderLibTest, NopTransactionClear) {
- status_t ret;
Parcel data, reply;
// make sure it accepts the transaction flag
- ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_CLEAR_BUF);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_CLEAR_BUF),
+ StatusEq(NO_ERROR));
}
TEST_F(BinderLibTest, Freeze) {
- status_t ret;
Parcel data, reply, replypid;
std::ifstream freezer_file("/sys/fs/cgroup/freezer/cgroup.freeze");
@@ -442,9 +443,8 @@
return;
}
- ret = m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid), StatusEq(NO_ERROR));
int32_t pid = replypid.readInt32();
- EXPECT_EQ(NO_ERROR, ret);
for (int i = 0; i < 10; i++) {
EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY));
}
@@ -468,42 +468,36 @@
TEST_F(BinderLibTest, SetError) {
int32_t testValue[] = { 0, -123, 123 };
for (size_t i = 0; i < ARRAY_SIZE(testValue); i++) {
- status_t ret;
Parcel data, reply;
data.writeInt32(testValue[i]);
- ret = m_server->transact(BINDER_LIB_TEST_SET_ERROR_TRANSACTION, data, &reply);
- EXPECT_EQ(testValue[i], ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_SET_ERROR_TRANSACTION, data, &reply),
+ StatusEq(testValue[i]));
}
}
TEST_F(BinderLibTest, GetId) {
- status_t ret;
int32_t id;
Parcel data, reply;
- ret = m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
- ret = reply.readInt32(&id);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
+ EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
EXPECT_EQ(0, id);
}
TEST_F(BinderLibTest, PtrSize) {
- status_t ret;
int32_t ptrsize;
Parcel data, reply;
sp<IBinder> server = addServer();
ASSERT_TRUE(server != nullptr);
- ret = server->transact(BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
- ret = reply.readInt32(&ptrsize);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
+ EXPECT_THAT(reply.readInt32(&ptrsize), StatusEq(NO_ERROR));
RecordProperty("TestPtrSize", sizeof(void *));
RecordProperty("ServerPtrSize", sizeof(void *));
}
TEST_F(BinderLibTest, IndirectGetId2)
{
- status_t ret;
int32_t id;
int32_t count;
Parcel data, reply;
@@ -521,22 +515,19 @@
datai.appendTo(&data);
}
- ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_THAT(m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
- ret = reply.readInt32(&id);
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
EXPECT_EQ(0, id);
- ret = reply.readInt32(&count);
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_THAT(reply.readInt32(&count), StatusEq(NO_ERROR));
EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count);
for (size_t i = 0; i < (size_t)count; i++) {
BinderLibTestBundle replyi(&reply);
EXPECT_TRUE(replyi.isValid());
- ret = replyi.readInt32(&id);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(replyi.readInt32(&id), StatusEq(NO_ERROR));
EXPECT_EQ(serverId[i], id);
EXPECT_EQ(replyi.dataSize(), replyi.dataPosition());
}
@@ -546,7 +537,6 @@
TEST_F(BinderLibTest, IndirectGetId3)
{
- status_t ret;
int32_t id;
int32_t count;
Parcel data, reply;
@@ -571,15 +561,13 @@
datai.appendTo(&data);
}
- ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_THAT(m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
- ret = reply.readInt32(&id);
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
EXPECT_EQ(0, id);
- ret = reply.readInt32(&count);
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_THAT(reply.readInt32(&count), StatusEq(NO_ERROR));
EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count);
for (size_t i = 0; i < (size_t)count; i++) {
@@ -587,18 +575,15 @@
BinderLibTestBundle replyi(&reply);
EXPECT_TRUE(replyi.isValid());
- ret = replyi.readInt32(&id);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(replyi.readInt32(&id), StatusEq(NO_ERROR));
EXPECT_EQ(serverId[i], id);
- ret = replyi.readInt32(&counti);
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_THAT(replyi.readInt32(&counti), StatusEq(NO_ERROR));
EXPECT_EQ(1, counti);
BinderLibTestBundle replyi2(&replyi);
EXPECT_TRUE(replyi2.isValid());
- ret = replyi2.readInt32(&id);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(replyi2.readInt32(&id), StatusEq(NO_ERROR));
EXPECT_EQ(0, id);
EXPECT_EQ(replyi2.dataSize(), replyi2.dataPosition());
@@ -610,16 +595,13 @@
TEST_F(BinderLibTest, CallBack)
{
- status_t ret;
Parcel data, reply;
sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
data.writeStrongBinder(callBack);
- ret = m_server->transact(BINDER_LIB_TEST_NOP_CALL_BACK, data, &reply, TF_ONE_WAY);
- EXPECT_EQ(NO_ERROR, ret);
- ret = callBack->waitEvent(5);
- EXPECT_EQ(NO_ERROR, ret);
- ret = callBack->getResult();
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_CALL_BACK, data, &reply, TF_ONE_WAY),
+ StatusEq(NO_ERROR));
+ EXPECT_THAT(callBack->waitEvent(5), StatusEq(NO_ERROR));
+ EXPECT_THAT(callBack->getResult(), StatusEq(NO_ERROR));
}
TEST_F(BinderLibTest, AddServer)
@@ -630,7 +612,6 @@
TEST_F(BinderLibTest, DeathNotificationStrongRef)
{
- status_t ret;
sp<IBinder> sbinder;
sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient();
@@ -638,20 +619,17 @@
{
sp<IBinder> binder = addServer();
ASSERT_TRUE(binder != nullptr);
- ret = binder->linkToDeath(testDeathRecipient);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(binder->linkToDeath(testDeathRecipient), StatusEq(NO_ERROR));
sbinder = binder;
}
{
Parcel data, reply;
- ret = sbinder->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY);
- EXPECT_EQ(0, ret);
+ EXPECT_THAT(sbinder->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY),
+ StatusEq(OK));
}
IPCThreadState::self()->flushCommands();
- ret = testDeathRecipient->waitEvent(5);
- EXPECT_EQ(NO_ERROR, ret);
- ret = sbinder->unlinkToDeath(testDeathRecipient);
- EXPECT_EQ(DEAD_OBJECT, ret);
+ EXPECT_THAT(testDeathRecipient->waitEvent(5), StatusEq(NO_ERROR));
+ EXPECT_THAT(sbinder->unlinkToDeath(testDeathRecipient), StatusEq(DEAD_OBJECT));
}
TEST_F(BinderLibTest, DeathNotificationMultiple)
@@ -674,8 +652,9 @@
callBack[i] = new BinderLibTestCallBack();
data.writeStrongBinder(target);
data.writeStrongBinder(callBack[i]);
- ret = linkedclient[i]->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(linkedclient[i]->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data,
+ &reply, TF_ONE_WAY),
+ StatusEq(NO_ERROR));
}
{
Parcel data, reply;
@@ -683,8 +662,9 @@
passiveclient[i] = addServer();
ASSERT_TRUE(passiveclient[i] != nullptr);
data.writeStrongBinder(target);
- ret = passiveclient[i]->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data, &reply, TF_ONE_WAY);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(passiveclient[i]->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data,
+ &reply, TF_ONE_WAY),
+ StatusEq(NO_ERROR));
}
}
{
@@ -694,10 +674,8 @@
}
for (int i = 0; i < clientcount; i++) {
- ret = callBack[i]->waitEvent(5);
- EXPECT_EQ(NO_ERROR, ret);
- ret = callBack[i]->getResult();
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(callBack[i]->waitEvent(5), StatusEq(NO_ERROR));
+ EXPECT_THAT(callBack[i]->getResult(), StatusEq(NO_ERROR));
}
}
@@ -712,8 +690,7 @@
sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient();
- ret = target->linkToDeath(testDeathRecipient);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(target->linkToDeath(testDeathRecipient), StatusEq(NO_ERROR));
{
Parcel data, reply;
@@ -750,14 +727,13 @@
callback = new BinderLibTestCallBack();
data.writeStrongBinder(target);
data.writeStrongBinder(callback);
- ret = client->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(client->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply,
+ TF_ONE_WAY),
+ StatusEq(NO_ERROR));
}
- ret = callback->waitEvent(5);
- EXPECT_EQ(NO_ERROR, ret);
- ret = callback->getResult();
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(callback->waitEvent(5), StatusEq(NO_ERROR));
+ EXPECT_THAT(callback->getResult(), StatusEq(NO_ERROR));
}
TEST_F(BinderLibTest, PassFile) {
@@ -773,17 +749,14 @@
Parcel data, reply;
uint8_t writebuf[1] = { write_value };
- ret = data.writeFileDescriptor(pipefd[1], true);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(data.writeFileDescriptor(pipefd[1], true), StatusEq(NO_ERROR));
- ret = data.writeInt32(sizeof(writebuf));
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(data.writeInt32(sizeof(writebuf)), StatusEq(NO_ERROR));
- ret = data.write(writebuf, sizeof(writebuf));
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(data.write(writebuf, sizeof(writebuf)), StatusEq(NO_ERROR));
- ret = m_server->transact(BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
}
ret = read(pipefd[0], buf, sizeof(buf));
@@ -864,11 +837,10 @@
}
TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) {
- status_t ret;
Parcel data, reply;
- ret = m_server->transact(BINDER_LIB_TEST_GET_SELF_TRANSACTION, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GET_SELF_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
const flat_binder_object *fb = reply.readObject(false);
ASSERT_TRUE(fb != nullptr);
@@ -888,8 +860,8 @@
wp<IBinder> keepFreedBinder;
{
Parcel data, reply;
- ret = server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply);
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_THAT(server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
struct flat_binder_object *freed = (struct flat_binder_object *)(reply.data());
freedHandle = freed->handle;
/* Add a weak ref to the freed binder so the driver does not
@@ -950,7 +922,6 @@
}
TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) {
- status_t ret;
Parcel data, reply;
sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
for (int i = 0; i < 2; i++) {
@@ -964,13 +935,12 @@
datai.appendTo(&data);
}
- ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply),
+ StatusEq(NO_ERROR));
}
TEST_F(BinderLibTest, OnewayQueueing)
{
- status_t ret;
Parcel data, data2;
sp<IBinder> pollServer = addPollServer();
@@ -983,25 +953,21 @@
data2.writeStrongBinder(callBack2);
data2.writeInt32(0); // delay in us
- ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, nullptr, TF_ONE_WAY);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, nullptr, TF_ONE_WAY),
+ StatusEq(NO_ERROR));
// The delay ensures that this second transaction will end up on the async_todo list
// (for a single-threaded server)
- ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, nullptr, TF_ONE_WAY);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, nullptr, TF_ONE_WAY),
+ StatusEq(NO_ERROR));
// The server will ensure that the two transactions are handled in the expected order;
// If the ordering is not as expected, an error will be returned through the callbacks.
- ret = callBack->waitEvent(2);
- EXPECT_EQ(NO_ERROR, ret);
- ret = callBack->getResult();
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(callBack->waitEvent(2), StatusEq(NO_ERROR));
+ EXPECT_THAT(callBack->getResult(), StatusEq(NO_ERROR));
- ret = callBack2->waitEvent(2);
- EXPECT_EQ(NO_ERROR, ret);
- ret = callBack2->getResult();
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(callBack2->waitEvent(2), StatusEq(NO_ERROR));
+ EXPECT_THAT(callBack2->getResult(), StatusEq(NO_ERROR));
}
TEST_F(BinderLibTest, WorkSourceUnsetByDefault)
@@ -1120,8 +1086,8 @@
ASSERT_TRUE(server != nullptr);
Parcel data, reply;
- status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply),
+ StatusEq(NO_ERROR));
int policy = reply.readInt32();
int priority = reply.readInt32();
@@ -1140,8 +1106,8 @@
EXPECT_EQ(0, sched_setscheduler(getpid(), SCHED_RR, ¶m));
Parcel data, reply;
- status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply),
+ StatusEq(NO_ERROR));
int policy = reply.readInt32();
int priority = reply.readInt32();
@@ -1158,10 +1124,9 @@
std::vector<uint64_t> const testValue = { std::numeric_limits<uint64_t>::max(), 0, 200 };
data.writeUint64Vector(testValue);
- status_t ret = server->transact(BINDER_LIB_TEST_ECHO_VECTOR, data, &reply);
- EXPECT_EQ(NO_ERROR, ret);
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_ECHO_VECTOR, data, &reply), StatusEq(NO_ERROR));
std::vector<uint64_t> readValue;
- ret = reply.readUint64Vector(&readValue);
+ EXPECT_THAT(reply.readUint64Vector(&readValue), StatusEq(OK));
EXPECT_EQ(readValue, testValue);
}
@@ -1186,19 +1151,18 @@
memcpy(parcelData, &obj, sizeof(obj));
data.setDataSize(sizeof(obj));
- status_t ret = server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply);
// Either the kernel should reject this transaction (if it's correct), but
// if it's not, the server implementation should return an error if it
// finds an object in the received Parcel.
- EXPECT_NE(NO_ERROR, ret);
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply),
+ Not(StatusEq(NO_ERROR)));
}
TEST_F(BinderLibTest, GotSid) {
sp<IBinder> server = addServer();
Parcel data;
- status_t ret = server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr);
- EXPECT_EQ(OK, ret);
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
}
class BinderLibTestService : public BBinder
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index b3ce744..260be57 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -929,6 +929,34 @@
}),
PrintSocketType);
+class BinderRpcServerRootObject : public ::testing::TestWithParam<std::tuple<bool, bool>> {};
+
+TEST_P(BinderRpcServerRootObject, WeakRootObject) {
+ using SetFn = std::function<void(RpcServer*, sp<IBinder>)>;
+ auto setRootObject = [](bool isStrong) -> SetFn {
+ return isStrong ? SetFn(&RpcServer::setRootObject) : SetFn(&RpcServer::setRootObjectWeak);
+ };
+
+ auto server = RpcServer::make();
+ auto [isStrong1, isStrong2] = GetParam();
+ auto binder1 = sp<BBinder>::make();
+ IBinder* binderRaw1 = binder1.get();
+ setRootObject(isStrong1)(server.get(), binder1);
+ EXPECT_EQ(binderRaw1, server->getRootObject());
+ binder1.clear();
+ EXPECT_EQ((isStrong1 ? binderRaw1 : nullptr), server->getRootObject());
+
+ auto binder2 = sp<BBinder>::make();
+ IBinder* binderRaw2 = binder2.get();
+ setRootObject(isStrong2)(server.get(), binder2);
+ EXPECT_EQ(binderRaw2, server->getRootObject());
+ binder2.clear();
+ EXPECT_EQ((isStrong2 ? binderRaw2 : nullptr), server->getRootObject());
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerRootObject,
+ ::testing::Combine(::testing::Bool(), ::testing::Bool()));
+
} // namespace android
int main(int argc, char** argv) {
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
new file mode 100644
index 0000000..1c75306
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -0,0 +1,40 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_fuzz {
+ name: "binder_rpc_fuzzer",
+ host_supported: true,
+
+ fuzz_config: {
+ cc: ["smoreland@google.com"],
+ },
+
+ srcs: [
+ "main.cpp",
+ ],
+ static_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+
+ target: {
+ android: {
+ shared_libs: [
+ "libbinder",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libbinder",
+ ],
+ },
+ },
+}
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
new file mode 100644
index 0000000..3603ebe
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/Binder.h>
+#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+
+#include <sys/resource.h>
+#include <sys/un.h>
+
+namespace android {
+
+static const std::string kSock = std::string(getenv("TMPDIR") ?: "/tmp") +
+ "/binderRpcFuzzerSocket_" + std::to_string(getpid());
+
+size_t getHardMemoryLimit() {
+ struct rlimit limit;
+ CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
+ return limit.rlim_max;
+}
+
+void setMemoryLimit(size_t cur, size_t max) {
+ const struct rlimit kLimit = {
+ .rlim_cur = cur,
+ .rlim_max = max,
+ };
+ CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
+}
+
+class SomeBinder : public BBinder {
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) {
+ (void)flags;
+
+ if ((code & 1) == 0) {
+ sp<IBinder> binder;
+ (void)data.readStrongBinder(&binder);
+ if (binder != nullptr) {
+ (void)binder->pingBinder();
+ }
+ }
+ if ((code & 2) == 0) {
+ (void)data.readInt32();
+ }
+ if ((code & 4) == 0) {
+ (void)reply->writeStrongBinder(sp<BBinder>::make());
+ }
+
+ return OK;
+ }
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size > 50000) return 0;
+
+ unlink(kSock.c_str());
+
+ sp<RpcServer> server = RpcServer::make();
+ server->setRootObject(sp<SomeBinder>::make());
+ server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ CHECK(server->setupUnixDomainServer(kSock.c_str()));
+
+ static constexpr size_t kMemLimit = 1llu * 1024 * 1024 * 1024;
+ size_t hardLimit = getHardMemoryLimit();
+ setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
+
+ std::thread serverThread([=] { (void)server->acceptOne(); });
+
+ sockaddr_un addr{
+ .sun_family = AF_UNIX,
+ };
+ CHECK_LT(kSock.size(), sizeof(addr.sun_path));
+ memcpy(&addr.sun_path, kSock.c_str(), kSock.size());
+
+ base::unique_fd clientFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ CHECK_NE(clientFd.get(), -1);
+ CHECK_EQ(0,
+ TEMP_FAILURE_RETRY(
+ connect(clientFd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))))
+ << strerror(errno);
+
+ serverThread.join();
+
+ // TODO(b/182938024): fuzz multiple sessions, instead of just one
+
+#if 0
+ // make fuzzer more productive locally by forcing it to create a new session
+ int32_t id = -1;
+ CHECK(base::WriteFully(clientFd, &id, sizeof(id)));
+#endif
+
+ CHECK(base::WriteFully(clientFd, data, size));
+
+ clientFd.reset();
+
+ // TODO(b/185167543): better way to force a server to shutdown
+ while (!server->listSessions().empty() && server->numUninitializedSessions()) {
+ usleep(1);
+ }
+
+ setMemoryLimit(hardLimit, hardLimit);
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 41dd7bf..d94347a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -66,10 +66,70 @@
}
}
+status_t BufferStateLayer::addReleaseFence(const sp<CallbackHandle>& ch,
+ const sp<Fence>& fence) {
+ if (ch == nullptr) {
+ return OK;
+ }
+ if (!ch->previousReleaseFence.get()) {
+ ch->previousReleaseFence = fence;
+ return OK;
+ }
+
+ // Below logic is lifted from ConsumerBase.cpp:
+ // Check status of fences first because merging is expensive.
+ // Merging an invalid fence with any other fence results in an
+ // invalid fence.
+ auto currentStatus = ch->previousReleaseFence->getStatus();
+ if (currentStatus == Fence::Status::Invalid) {
+ ALOGE("Existing fence has invalid state, layer: %s", mName.c_str());
+ return BAD_VALUE;
+ }
+
+ auto incomingStatus = fence->getStatus();
+ if (incomingStatus == Fence::Status::Invalid) {
+ ALOGE("New fence has invalid state, layer: %s", mName.c_str());
+ ch->previousReleaseFence = fence;
+ return BAD_VALUE;
+ }
+
+ // If both fences are signaled or both are unsignaled, we need to merge
+ // them to get an accurate timestamp.
+ if (currentStatus == incomingStatus) {
+ char fenceName[32] = {};
+ snprintf(fenceName, 32, "%.28s", mName.c_str());
+ sp<Fence> mergedFence = Fence::merge(
+ fenceName, ch->previousReleaseFence, fence);
+ if (!mergedFence.get()) {
+ ALOGE("failed to merge release fences, layer: %s", mName.c_str());
+ // synchronization is broken, the best we can do is hope fences
+ // signal in order so the new fence will act like a union
+ ch->previousReleaseFence = fence;
+ return BAD_VALUE;
+ }
+ ch->previousReleaseFence = mergedFence;
+ } else if (incomingStatus == Fence::Status::Unsignaled) {
+ // If one fence has signaled and the other hasn't, the unsignaled
+ // fence will approximately correspond with the correct timestamp.
+ // There's a small race if both fences signal at about the same time
+ // and their statuses are retrieved with unfortunate timing. However,
+ // by this point, they will have both signaled and only the timestamp
+ // will be slightly off; any dependencies after this point will
+ // already have been met.
+ ch->previousReleaseFence = fence;
+ }
+ // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
+
+ return OK;
+}
+
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ if (!releaseFence->isValid()) {
+ return;
+ }
// The previous release fence notifies the client that SurfaceFlinger is done with the previous
// buffer that was presented on this layer. The first transaction that came in this frame that
// replaced the previous buffer on this layer needs this release fence, because the fence will
@@ -86,12 +146,17 @@
// buffer. It replaces the buffer in the second transaction. The buffer in the second
// transaction will now no longer be presented so it is released immediately and the third
// transaction doesn't need a previous release fence.
+ sp<CallbackHandle> ch;
for (auto& handle : mDrawingState.callbackHandles) {
if (handle->releasePreviousBuffer) {
- handle->previousReleaseFence = releaseFence;
+ ch = handle;
break;
}
}
+ auto status = addReleaseFence(ch, releaseFence);
+ if (status != OK) {
+ ALOGE("Failed to add release fence for layer %s", getName().c_str());
+ }
mPreviousReleaseFence = releaseFence;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 00fa7f7..2430c4e 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -120,6 +120,8 @@
bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
nsecs_t requestedPresentTime);
+ status_t addReleaseFence(const sp<CallbackHandle>& ch, const sp<Fence>& releaseFence);
+
uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;