summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartijn Coenen <maco@google.com>2017-08-15 19:39:36 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2017-08-15 19:39:36 +0000
commit99e17ff8cbffd1ca0a42e10d4c800e35dced7886 (patch)
tree8d4e4dfd2bc70c50d784fc231b6848885245dcf5
parent87ffcc425e479acf233996e8383890507c60bc49 (diff)
parentfb368f762fa17d1456f153bc3d67d4de4c452472 (diff)
downloadnative-99e17ff8cbffd1ca0a42e10d4c800e35dced7886.tar.gz
Merge changes I1c5b075b,I4bf5b314android-o-iot-preview-5o-iot-preview-5
* changes: Fix BINDER_LIB_TEST_NOP_CALL_BACK. Add test for async transaction queueing.
-rw-r--r--libs/binder/tests/binderLibTest.cpp188
1 files changed, 175 insertions, 13 deletions
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 71aa9a305d..1611e11209 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -28,6 +28,8 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <sys/epoll.h>
+
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
using namespace android;
@@ -50,8 +52,10 @@ enum BinderLibTestTranscationCode {
BINDER_LIB_TEST_NOP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
BINDER_LIB_TEST_REGISTER_SERVER,
BINDER_LIB_TEST_ADD_SERVER,
+ BINDER_LIB_TEST_ADD_POLL_SERVER,
BINDER_LIB_TEST_CALL_BACK,
BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF,
+ BINDER_LIB_TEST_DELAYED_CALL_BACK,
BINDER_LIB_TEST_NOP_CALL_BACK,
BINDER_LIB_TEST_GET_SELF_TRANSACTION,
BINDER_LIB_TEST_GET_ID_TRANSACTION,
@@ -68,7 +72,7 @@ enum BinderLibTestTranscationCode {
BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
};
-pid_t start_server_process(int arg2)
+pid_t start_server_process(int arg2, bool usePoll = false)
{
int ret;
pid_t pid;
@@ -76,11 +80,13 @@ pid_t start_server_process(int arg2)
int pipefd[2];
char stri[16];
char strpipefd1[16];
+ char usepoll[2];
char *childargv[] = {
binderservername,
binderserverarg,
stri,
strpipefd1,
+ usepoll,
binderserversuffix,
NULL
};
@@ -91,6 +97,7 @@ pid_t start_server_process(int arg2)
snprintf(stri, sizeof(stri), "%d", arg2);
snprintf(strpipefd1, sizeof(strpipefd1), "%d", pipefd[1]);
+ snprintf(usepoll, sizeof(usepoll), "%d", usePoll ? 1 : 0);
pid = fork();
if (pid == -1)
@@ -175,14 +182,14 @@ class BinderLibTest : public ::testing::Test {
virtual void TearDown() {
}
protected:
- sp<IBinder> addServer(int32_t *idPtr = NULL)
+ sp<IBinder> addServerEtc(int32_t *idPtr, int code)
{
int ret;
int32_t id;
Parcel data, reply;
sp<IBinder> binder;
- ret = m_server->transact(BINDER_LIB_TEST_ADD_SERVER, data, &reply);
+ ret = m_server->transact(code, data, &reply);
EXPECT_EQ(NO_ERROR, ret);
EXPECT_FALSE(binder != NULL);
@@ -194,6 +201,17 @@ class BinderLibTest : public ::testing::Test {
*idPtr = id;
return binder;
}
+
+ sp<IBinder> addServer(int32_t *idPtr = NULL)
+ {
+ return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_SERVER);
+ }
+
+ sp<IBinder> addPollServer(int32_t *idPtr = NULL)
+ {
+ return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_POLL_SERVER);
+ }
+
void waitForReadData(int fd, int timeout_ms) {
int ret;
pollfd pfd = pollfd();
@@ -313,10 +331,14 @@ class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent
(void)reply;
(void)flags;
switch(code) {
- case BINDER_LIB_TEST_CALL_BACK:
- m_result = data.readInt32();
+ case BINDER_LIB_TEST_CALL_BACK: {
+ status_t status = data.readInt32(&m_result);
+ if (status != NO_ERROR) {
+ m_result = status;
+ }
triggerEvent();
return NO_ERROR;
+ }
case BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF: {
sp<IBinder> server;
int ret;
@@ -844,6 +866,42 @@ TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) {
EXPECT_EQ(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, OnewayQueueing)
+{
+ status_t ret;
+ Parcel data, data2;
+
+ sp<IBinder> pollServer = addPollServer();
+
+ sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
+ data.writeStrongBinder(callBack);
+ data.writeInt32(500000); // delay in us before calling back
+
+ sp<BinderLibTestCallBack> callBack2 = new BinderLibTestCallBack();
+ data2.writeStrongBinder(callBack2);
+ data2.writeInt32(0); // delay in us
+
+ ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, NULL, TF_ONE_WAY);
+ EXPECT_EQ(NO_ERROR, ret);
+
+ // 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, NULL, TF_ONE_WAY);
+ EXPECT_EQ(NO_ERROR, ret);
+
+ // 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);
+
+ ret = callBack2->waitEvent(2);
+ EXPECT_EQ(NO_ERROR, ret);
+ ret = callBack2->getResult();
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
class BinderLibTestService : public BBinder
{
public:
@@ -851,6 +909,7 @@ class BinderLibTestService : public BBinder
: m_id(id)
, m_nextServerId(id + 1)
, m_serverStartRequested(false)
+ , m_callback(NULL)
{
pthread_mutex_init(&m_serverWaitMutex, NULL);
pthread_cond_init(&m_serverWaitCond, NULL);
@@ -859,6 +918,16 @@ class BinderLibTestService : public BBinder
{
exit(EXIT_SUCCESS);
}
+
+ void processPendingCall() {
+ if (m_callback != NULL) {
+ Parcel data;
+ data.writeInt32(NO_ERROR);
+ m_callback->transact(BINDER_LIB_TEST_CALL_BACK, data, nullptr, TF_ONE_WAY);
+ m_callback = NULL;
+ }
+ }
+
virtual status_t onTransact(uint32_t code,
const Parcel& data, Parcel* reply,
uint32_t flags = 0) {
@@ -890,6 +959,7 @@ class BinderLibTestService : public BBinder
pthread_mutex_unlock(&m_serverWaitMutex);
return NO_ERROR;
}
+ case BINDER_LIB_TEST_ADD_POLL_SERVER:
case BINDER_LIB_TEST_ADD_SERVER: {
int ret;
uint8_t buf[1] = { 0 };
@@ -904,9 +974,10 @@ class BinderLibTestService : public BBinder
} else {
serverid = m_nextServerId++;
m_serverStartRequested = true;
+ bool usePoll = code == BINDER_LIB_TEST_ADD_POLL_SERVER;
pthread_mutex_unlock(&m_serverWaitMutex);
- ret = start_server_process(serverid);
+ ret = start_server_process(serverid, usePoll);
pthread_mutex_lock(&m_serverWaitMutex);
}
if (ret > 0) {
@@ -934,6 +1005,42 @@ class BinderLibTestService : public BBinder
}
case BINDER_LIB_TEST_NOP_TRANSACTION:
return NO_ERROR;
+ case BINDER_LIB_TEST_DELAYED_CALL_BACK: {
+ // Note: this transaction is only designed for use with a
+ // poll() server. See comments around epoll_wait().
+ if (m_callback != NULL) {
+ // A callback was already pending; this means that
+ // we received a second call while still processing
+ // the first one. Fail the test.
+ sp<IBinder> callback = data.readStrongBinder();
+ Parcel data2;
+ data2.writeInt32(UNKNOWN_ERROR);
+
+ callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, NULL, TF_ONE_WAY);
+ } else {
+ m_callback = data.readStrongBinder();
+ int32_t delayUs = data.readInt32();
+ /*
+ * It's necessary that we sleep here, so the next
+ * transaction the caller makes will be queued to
+ * the async queue.
+ */
+ usleep(delayUs);
+
+ /*
+ * Now when we return, libbinder will tell the kernel
+ * we are done with this transaction, and the kernel
+ * can move the queued transaction to either the
+ * thread todo worklist (for kernels without the fix),
+ * or the proc todo worklist. In case of the former,
+ * the next outbound call will pick up the pending
+ * transaction, which leads to undesired reentrant
+ * behavior. This is caught in the if() branch above.
+ */
+ }
+
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_NOP_CALL_BACK: {
Parcel data2, reply2;
sp<IBinder> binder;
@@ -941,7 +1048,7 @@ class BinderLibTestService : public BBinder
if (binder == NULL) {
return BAD_VALUE;
}
- reply2.writeInt32(NO_ERROR);
+ data2.writeInt32(NO_ERROR);
binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2);
return NO_ERROR;
}
@@ -1083,16 +1190,26 @@ class BinderLibTestService : public BBinder
bool m_serverStartRequested;
sp<IBinder> m_serverStarted;
sp<IBinder> m_strongRef;
+ bool m_callbackPending;
+ sp<IBinder> m_callback;
};
-int run_server(int index, int readypipefd)
+int run_server(int index, int readypipefd, bool usePoll)
{
binderLibTestServiceName += String16(binderserversuffix);
status_t ret;
sp<IServiceManager> sm = defaultServiceManager();
+ BinderLibTestService* testServicePtr;
{
sp<BinderLibTestService> testService = new BinderLibTestService(index);
+ /*
+ * We need this below, but can't hold a sp<> because it prevents the
+ * node from being cleaned up automatically. It's safe in this case
+ * because of how the tests are written.
+ */
+ testServicePtr = testService.get();
+
if (index == 0) {
ret = sm->addService(binderLibTestServiceName, testService);
} else {
@@ -1110,8 +1227,53 @@ int run_server(int index, int readypipefd)
if (ret)
return 1;
//printf("%s: joinThreadPool\n", __func__);
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
+ if (usePoll) {
+ int fd;
+ struct epoll_event ev;
+ int epoll_fd;
+ IPCThreadState::self()->setupPolling(&fd);
+ if (fd < 0) {
+ return 1;
+ }
+ IPCThreadState::self()->flushCommands(); // flush BC_ENTER_LOOPER
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ return 1;
+ }
+
+ ev.events = EPOLLIN;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ return 1;
+ }
+
+ while (1) {
+ /*
+ * We simulate a single-threaded process using the binder poll
+ * interface; besides handling binder commands, it can also
+ * issue outgoing transactions, by storing a callback in
+ * m_callback and setting m_callbackPending.
+ *
+ * processPendingCall() will then issue that transaction.
+ */
+ struct epoll_event events[1];
+ int numEvents = epoll_wait(epoll_fd, events, 1, 1000);
+ if (numEvents < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return 1;
+ }
+ if (numEvents > 0) {
+ IPCThreadState::self()->handlePolledCommands();
+ IPCThreadState::self()->flushCommands(); // flush BC_FREE_BUFFER
+ testServicePtr->processPendingCall();
+ }
+ }
+ } else {
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ }
//printf("%s: joinThreadPool returned\n", __func__);
return 1; /* joinThreadPool should not return */
}
@@ -1125,9 +1287,9 @@ int main(int argc, char **argv) {
binderservername = argv[0];
}
- if (argc == 5 && !strcmp(argv[1], binderserverarg)) {
- binderserversuffix = argv[4];
- return run_server(atoi(argv[2]), atoi(argv[3]));
+ if (argc == 6 && !strcmp(argv[1], binderserverarg)) {
+ binderserversuffix = argv[5];
+ return run_server(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) == 1);
}
binderserversuffix = new char[16];
snprintf(binderserversuffix, 16, "%d", getpid());