Add support for file descriptors
Change-Id: I172cbb02bbb034ca5d41b1958674b22bb8a7f93e
Test: Expanded unit tests
Bug: 25242023
Signed-off-by: Casey Dahlin <sadmac@google.com>
diff --git a/tests/aidl_test_client.cpp b/tests/aidl_test_client.cpp
index e9df4b5..976dc37 100644
--- a/tests/aidl_test_client.cpp
+++ b/tests/aidl_test_client.cpp
@@ -17,6 +17,11 @@
#include <iostream>
#include <vector>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nativehelper/ScopedFd.h>
#include <binder/IServiceManager.h>
#include <utils/String8.h>
#include <utils/String16.h>
@@ -45,6 +50,7 @@
using std::cerr;
using std::cout;
using std::endl;
+using std::string;
using std::vector;
namespace {
@@ -284,6 +290,123 @@
return true;
}
+
+#define FdByName(_fd) #_fd, _fd
+
+bool DoWrite(string name, const ScopedFd& fd, const string& buf) {
+ int wrote;
+
+ while ((wrote = write(fd.get(), buf.data(), buf.size())) < 0 && errno == EINTR);
+
+ if (wrote == (signed)buf.size()) {
+ return true;
+ }
+
+ if (wrote < 0) {
+ cerr << "Error writing to file descriptor '" << name << "': "
+ << strerror(errno) << endl;
+ } else {
+ cerr << "File descriptor '" << name << "'accepted short data." << endl;
+ }
+
+ return false;
+}
+
+bool DoRead(string name, const ScopedFd& fd, const string& expected) {
+ size_t length = expected.size();
+ int got;
+ string buf;
+ buf.resize(length);
+
+ while ((got = read(fd.get(), &buf[0], length)) < 0 && errno == EINTR);
+
+ if (got < 0) {
+ cerr << "Error reading from '" << name << "': " << strerror(errno) << endl;
+ return false;
+ }
+
+ if (buf != expected) {
+ cerr << "Expected '" << expected << "' got '" << buf << "'" << endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool DoPipe(ScopedFd* read_side, ScopedFd* write_side) {
+ int fds[2];
+ ScopedFd return_fd;
+
+ if (pipe(fds)) {
+ cout << "Error creating pipes: " << strerror(errno) << endl;
+ return false;
+ }
+
+ read_side->reset(fds[0]);
+ write_side->reset(fds[1]);
+ return true;
+}
+
+bool ConfirmFileDescriptors(const sp<ITestService>& s) {
+ Status status;
+ cout << "Confirming passing and returning file descriptors works." << endl;
+
+ ScopedFd return_fd;
+ ScopedFd read_fd;
+ ScopedFd write_fd;
+
+ if (!DoPipe(&read_fd, &write_fd)) {
+ return false;
+ }
+
+ status = s->RepeatFileDescriptor(write_fd, &return_fd);
+
+ if (!status.isOk()) {
+ cerr << "Could not repeat file descriptors." << endl;
+ return false;
+ }
+
+ /* A note on some of the spookier stuff going on here: IIUC writes to pipes
+ * should be atomic and non-blocking so long as the total size doesn't exceed
+ * PIPE_BUF. We thus play a bit fast and loose with failure modes here.
+ */
+
+ bool ret =
+ DoWrite(FdByName(return_fd), "ReturnString") &&
+ DoRead(FdByName(read_fd), "ReturnString");
+
+ return ret;
+}
+
+bool ConfirmFileDescriptorArrays(const sp<ITestService>& s) {
+ Status status;
+ cout << "Confirming passing and returning file descriptor arrays works." << endl;
+
+ vector<ScopedFd> array;
+ array.resize(2);
+
+ if (!DoPipe(&array[0], &array[1])) {
+ return false;
+ }
+
+ vector<ScopedFd> repeated;
+ vector<ScopedFd> reversed;
+
+ status = s->ReverseFileDescriptorArray(array, &repeated, &reversed);
+
+ if (!status.isOk()) {
+ cerr << "Could not reverse file descriptor array." << endl;
+ return false;
+ }
+
+ bool ret =
+ DoWrite(FdByName(array[1]), "First") &&
+ DoWrite(FdByName(repeated[1]), "Second") &&
+ DoWrite(FdByName(reversed[0]), "Third") &&
+ DoRead(FdByName(reversed[1]), "FirstSecondThird");
+
+ return ret;
+}
} // namespace
int main(int /* argc */, char * /* argv */ []) {
@@ -301,5 +424,9 @@
if (!ConfirmReverseBinderLists(service)) return 1;
+ if (!ConfirmFileDescriptors(service)) return 1;
+
+ if (!ConfirmFileDescriptorArrays(service)) return 1;
+
return 0;
}