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);
 }