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;
}
diff --git a/tests/aidl_test_service.cpp b/tests/aidl_test_service.cpp
index 2d4487a..2b6b5fd 100644
--- a/tests/aidl_test_service.cpp
+++ b/tests/aidl_test_service.cpp
@@ -19,10 +19,13 @@
#include <string>
#include <vector>
+#include <unistd.h>
+
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <nativehelper/ScopedFd.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Looper.h>
@@ -179,8 +182,8 @@
}
Status RepeatParcelable(const SimpleParcelable& input,
- SimpleParcelable* repeat,
- SimpleParcelable* _aidl_return) override {
+ SimpleParcelable* repeat,
+ SimpleParcelable* _aidl_return) override {
ALOGI("Repeated a SimpleParcelable %s", input.toString().c_str());
*repeat = input;
*_aidl_return = input;
@@ -189,8 +192,8 @@
template<typename T>
Status ReverseArray(const vector<T>& input,
- vector<T>* repeated,
- vector<T>* _aidl_return) {
+ vector<T>* repeated,
+ vector<T>* _aidl_return) {
ALOGI("Reversing array of length %zu", input.size());
*repeated = input;
*_aidl_return = input;
@@ -199,53 +202,53 @@
}
Status ReverseBoolean(const vector<bool>& input,
- vector<bool>* repeated,
- vector<bool>* _aidl_return) override {
+ vector<bool>* repeated,
+ vector<bool>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseByte(const vector<int8_t>& input,
- vector<int8_t>* repeated,
- vector<int8_t>* _aidl_return) override {
+ vector<int8_t>* repeated,
+ vector<int8_t>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseChar(const vector<char16_t>& input,
- vector<char16_t>* repeated,
- vector<char16_t>* _aidl_return) override {
+ vector<char16_t>* repeated,
+ vector<char16_t>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseInt(const vector<int32_t>& input,
- vector<int32_t>* repeated,
- vector<int32_t>* _aidl_return) override {
+ vector<int32_t>* repeated,
+ vector<int32_t>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseLong(const vector<int64_t>& input,
- vector<int64_t>* repeated,
- vector<int64_t>* _aidl_return) override {
+ vector<int64_t>* repeated,
+ vector<int64_t>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseFloat(const vector<float>& input,
- vector<float>* repeated,
- vector<float>* _aidl_return) override {
+ vector<float>* repeated,
+ vector<float>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseDouble(const vector<double>& input,
- vector<double>* repeated,
- vector<double>* _aidl_return) override {
+ vector<double>* repeated,
+ vector<double>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseString(const vector<String16>& input,
- vector<String16>* repeated,
- vector<String16>* _aidl_return) override {
+ vector<String16>* repeated,
+ vector<String16>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseParcelables(const vector<SimpleParcelable>& input,
- vector<SimpleParcelable>* repeated,
- vector<SimpleParcelable>* _aidl_return) override {
+ vector<SimpleParcelable>* repeated,
+ vector<SimpleParcelable>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status GetOtherTestService(const String16& name,
- sp<INamedCallback>* returned_service) override {
+ sp<INamedCallback>* returned_service) override {
if (service_map_.find(name) == service_map_.end()) {
sp<INamedCallback> new_item(new NamedCallback(name));
service_map_[name] = new_item;
@@ -256,7 +259,7 @@
}
Status VerifyName(const sp<INamedCallback>& service, const String16& name,
- bool* returned_value) override {
+ bool* returned_value) override {
String16 foundName;
Status status = service->GetName(&foundName);
@@ -268,17 +271,36 @@
}
Status ReverseStringList(const vector<String16>& input,
- vector<String16>* repeated,
- vector<String16>* _aidl_return) override {
+ vector<String16>* repeated,
+ vector<String16>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
Status ReverseNamedCallbackList(const vector<sp<IBinder>>& input,
- vector<sp<IBinder>>* repeated,
- vector<sp<IBinder>>* _aidl_return) override {
+ vector<sp<IBinder>>* repeated,
+ vector<sp<IBinder>>* _aidl_return) override {
return ReverseArray(input, repeated, _aidl_return);
}
+ Status RepeatFileDescriptor(const ScopedFd& read,
+ ScopedFd* _aidl_return) override {
+ ALOGE("Repeating file descriptor");
+ *_aidl_return = ScopedFd(dup(read.get()));
+ return Status::ok();
+ }
+
+ Status ReverseFileDescriptorArray(const vector<ScopedFd>& input,
+ vector<ScopedFd>* repeated,
+ vector<ScopedFd>* _aidl_return) override {
+ ALOGI("Reversing descriptor array of length %zu", input.size());
+ for (const auto& item : input) {
+ repeated->push_back(ScopedFd(dup(item.get())));
+ _aidl_return->push_back(ScopedFd(dup(item.get())));
+ }
+ std::reverse(_aidl_return->begin(), _aidl_return->end());
+ return Status::ok();
+ }
+
private:
map<String16, sp<INamedCallback>> service_map_;
};
diff --git a/tests/android/aidl/tests/ITestService.aidl b/tests/android/aidl/tests/ITestService.aidl
index 9f054ad..3d750d7 100644
--- a/tests/android/aidl/tests/ITestService.aidl
+++ b/tests/android/aidl/tests/ITestService.aidl
@@ -55,4 +55,8 @@
out List<String> repeated);
List<IBinder> ReverseNamedCallbackList(in List<IBinder> input,
out List<IBinder> repeated);
+
+ FileDescriptor RepeatFileDescriptor(in FileDescriptor read);
+ FileDescriptor[] ReverseFileDescriptorArray(in FileDescriptor[] input,
+ out FileDescriptor[] repeated);
}