native_handle_t support.

- writeEmbeddedNativeHandle to write a native_handle_t*
  embedded inside a buffer.
- Factored out writeEmbeddedBuffer to make clear the buffer
  is pointed to from inside another buffer.
- readBuffer()/readEmbeddedBuffer()/readEmbeddedNativeHandle()
- Added writeNativeHandleNoDup()/readNativeHandleNoDup() to
  avoid copying file descriptors around if the caller doesn't
  need it.
- Moved the binder header modifications inside libhwbinder
  for now, until we can get them upstreamed and pulled down
  to bionic's uapi headers again.

Change-Id: I3a2c44732f5dc9ed92363552b42aa3ff55a06a8d
diff --git a/IPCThreadState.cpp b/IPCThreadState.cpp
index 7c0dc0a..dda2064 100644
--- a/IPCThreadState.cpp
+++ b/IPCThreadState.cpp
@@ -927,37 +927,36 @@
 status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
     int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
 {
-    binder_transaction_data tr;
-
-    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
-    tr.target.handle = handle;
-    tr.code = code;
-    tr.flags = binderFlags;
-    tr.cookie = 0;
-    tr.sender_pid = 0;
-    tr.sender_euid = 0;
+    binder_transaction_data_sg tr_sg;
+    tr_sg.tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
+    tr_sg.tr.target.handle = handle;
+    tr_sg.tr.code = code;
+    tr_sg.tr.flags = binderFlags;
+    tr_sg.tr.cookie = 0;
+    tr_sg.tr.sender_pid = 0;
+    tr_sg.tr.sender_euid = 0;
     
     const status_t err = data.errorCheck();
     if (err == NO_ERROR) {
-        tr.data_size = data.ipcDataSize();
-        tr.data.ptr.buffer = data.ipcData();
-        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
-        tr.data.ptr.offsets = data.ipcObjects();
-        tr.buffers_size = data.ipcBufferSize();
+        tr_sg.tr.data_size = data.ipcDataSize();
+        tr_sg.tr.data.ptr.buffer = data.ipcData();
+        tr_sg.tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
+        tr_sg.tr.data.ptr.offsets = data.ipcObjects();
+        tr_sg.buffers_size = data.ipcBufferSize();
     } else if (statusBuffer) {
-        tr.flags |= TF_STATUS_CODE;
+        tr_sg.tr.flags |= TF_STATUS_CODE;
         *statusBuffer = err;
-        tr.data_size = sizeof(status_t);
-        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
-        tr.offsets_size = 0;
-        tr.data.ptr.offsets = 0;
-        tr.buffers_size = 0;
+        tr_sg.tr.data_size = sizeof(status_t);
+        tr_sg.tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
+        tr_sg.tr.offsets_size = 0;
+        tr_sg.tr.data.ptr.offsets = 0;
+        tr_sg.buffers_size = 0;
     } else {
         return (mLastError = err);
     }
     
     mOut.writeInt32(cmd);
-    mOut.write(&tr, sizeof(tr));
+    mOut.write(&tr_sg, sizeof(tr_sg));
     
     return NO_ERROR;
 }
diff --git a/Parcel.cpp b/Parcel.cpp
index a8f1df2..b85f99d 100644
--- a/Parcel.cpp
+++ b/Parcel.cpp
@@ -168,6 +168,10 @@
             }
             return;
         }
+        case BINDER_TYPE_PTR:
+        case BINDER_TYPE_FDA: {
+            return;
+        }
     }
 
     ALOGD("Invalid object type 0x%08x", obj.type);
@@ -223,6 +227,14 @@
             }
             return;
         }
+        case BINDER_TYPE_PTR: {
+            // The relevant buffer is part of the transaction buffer and will be freed that way
+            return;
+        }
+        case BINDER_TYPE_FDA: {
+            // TODO free fdas
+            return;
+        }
     }
 
     ALOGE("Invalid object type 0x%08x", obj.type);
@@ -1353,18 +1365,18 @@
     goto restart_write;
 }
 
-status_t Parcel::writeBufferObject(const buffer_object& val)
+status_t Parcel::writeBufferObject(const binder_buffer_object& val)
 {
     const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
     const bool enoughObjects = mObjectsSize < mObjectsCapacity;
     if (enoughData && enoughObjects) {
 restart_write:
-        *reinterpret_cast<buffer_object*>(mData+mDataPos) = val;
+        *reinterpret_cast<binder_buffer_object*>(mData+mDataPos) = val;
 
         mObjects[mObjectsSize] = mDataPos;
         mObjectsSize++;
 
-        return finishWrite(sizeof(buffer_object));
+        return finishWrite(sizeof(binder_buffer_object));
     }
 
     if (!enoughData) {
@@ -1383,26 +1395,113 @@
     goto restart_write;
 }
 
-status_t Parcel::writeBuffer(void *buffer, size_t length, uint64_t *handle,
-                             uint64_t parent_handle, uint32_t parent_offset)
+status_t Parcel::writeEmbeddedBuffer(void *buffer, size_t length, uint64_t *handle,
+                             uint64_t parent_buffer_handle, uint64_t parent_offset)
 {
-    buffer_object obj;
+    binder_buffer_object obj;
     obj.type = BINDER_TYPE_PTR;
     obj.buffer = reinterpret_cast<uintptr_t>(buffer);
     obj.length = length;
+    obj.flags = BINDER_BUFFER_HAS_PARENT;
     if (handle != nullptr) {
         // We use an index into mObjects as a handle
         *handle = mObjectsSize;
     }
-    if (parent_handle != UINT64_MAX) {
-        // TODO verify parent
-        obj.parent = parent_handle;
-        obj.parent_offset = parent_offset; // TODO not safe on 32-bit
+    if (parent_buffer_handle < mObjectsSize) {
+        // TODO verify parent handle, parent itself
+        obj.parent = parent_buffer_handle;
+        obj.parent_offset = parent_offset; // TODO not safe on 32-bit binder, verify
     }
     // TODO we'll want to clean up object handling in general
     return writeBufferObject(obj);
 }
 
+status_t Parcel::writeBuffer(void *buffer, size_t length, uint64_t *handle)
+{
+    binder_buffer_object obj;
+    obj.type = BINDER_TYPE_PTR;
+    obj.buffer = reinterpret_cast<uintptr_t>(buffer);
+    obj.length = length;
+    obj.flags = 0;
+    if (handle != nullptr) {
+        // We use an index into mObjects as a handle
+        *handle = mObjectsSize;
+    }
+    // TODO we'll want to clean up object handling in general
+    return writeBufferObject(obj);
+}
+
+status_t Parcel::writeFileDescriptorArrayObject(const binder_fd_array_object& val)
+{
+    const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
+    const bool enoughObjects = mObjectsSize < mObjectsCapacity;
+    if (enoughData && enoughObjects) {
+restart_write:
+        *reinterpret_cast<binder_fd_array_object*>(mData+mDataPos) = val;
+
+        mObjects[mObjectsSize] = mDataPos;
+        mObjectsSize++;
+
+        return finishWrite(sizeof(binder_fd_array_object));
+    }
+
+    if (!enoughData) {
+        const status_t err = growData(sizeof(val));
+        if (err != NO_ERROR) return err;
+    }
+    if (!enoughObjects) {
+        size_t newSize = ((mObjectsSize+2)*3)/2;
+        if (newSize < mObjectsSize) return NO_MEMORY;   // overflow
+        binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
+        if (objects == NULL) return NO_MEMORY;
+        mObjects = objects;
+        mObjectsCapacity = newSize;
+    }
+
+    goto restart_write;
+}
+
+status_t Parcel::writeNativeHandleNoDup(const native_handle_t *handle)
+{
+    struct binder_fd_array_object fd_array;
+    uint64_t buffer_handle;
+    // A native handle consists of a buffer with file desctiptors inside
+    size_t native_handle_size = sizeof(native_handle_t) +
+        handle->numFds * sizeof(int) + handle->numInts * sizeof(int);
+    status_t status = writeBuffer((void*) handle, native_handle_size, &buffer_handle);
+    if (status != OK) {
+        return status;
+    }
+    fd_array.type = BINDER_TYPE_FDA;
+    fd_array.flags = 0;
+    fd_array.num_fds = handle->numFds;
+    fd_array.parent = buffer_handle;
+    fd_array.parent_offset = offsetof(native_handle_t, data);
+    return (writeFileDescriptorArrayObject(fd_array));
+}
+
+status_t Parcel::writeEmbeddedNativeHandle(const native_handle_t *handle,
+                                           uint64_t parent_buffer_handle,
+                                           uint64_t parent_offset)
+{
+    struct binder_fd_array_object fd_array;
+    uint64_t buffer_handle;
+    // A native handle consists of a buffer with file desctiptors inside
+    size_t native_handle_size = sizeof(native_handle_t) +
+        handle->numFds * sizeof(int) + handle->numInts * sizeof(int);
+    status_t status = writeEmbeddedBuffer((void*) handle, native_handle_size, &buffer_handle,
+            parent_buffer_handle, parent_offset);
+    if (status != OK) {
+        return status;
+    }
+    fd_array.type = BINDER_TYPE_FDA;
+    fd_array.flags = 0;
+    fd_array.num_fds = handle->numFds;
+    fd_array.parent = buffer_handle;
+    fd_array.parent_offset = offsetof(native_handle_t, data);
+    return (writeFileDescriptorArrayObject(fd_array));
+}
+
 status_t Parcel::writeNoException()
 {
     binder::Status status;
@@ -2038,7 +2137,6 @@
     return h;
 }
 
-
 int Parcel::readFileDescriptor() const
 {
     const flat_binder_object* flat = readObject(true);
@@ -2156,7 +2254,25 @@
     if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
         const flat_binder_object* obj
                 = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
-        mDataPos = DPOS + sizeof(flat_binder_object);
+        // TODO need to make sure current type still fits in remaining data buffer
+        switch (obj->type) {
+            case BINDER_TYPE_WEAK_BINDER:
+            case BINDER_TYPE_WEAK_HANDLE:
+            case BINDER_TYPE_BINDER:
+            case BINDER_TYPE_HANDLE:
+            case BINDER_TYPE_FD: {
+                mDataPos = DPOS + sizeof(flat_binder_object);
+                break;
+            }
+            case BINDER_TYPE_PTR: {
+                mDataPos = DPOS + sizeof(binder_buffer_object);
+                break;
+            }
+            case BINDER_TYPE_FDA: {
+                mDataPos = DPOS + sizeof(binder_fd_array_object);
+                break;
+            }
+        }
         if (!nullMetaData && (obj->cookie == 0 && obj->binder == 0)) {
             // When transferring a NULL object, we don't write it into
             // the object list, so we don't want to check for it when
@@ -2211,18 +2327,50 @@
     return NULL;
 }
 
-const void* Parcel::readBuffer() const
+const void* Parcel::readBuffer(uint64_t *buffer_handle) const
 {
-    const buffer_object* buffer_obj = (buffer_object*) readObject(true);
+    const binder_buffer_object* buffer_obj = (binder_buffer_object*) readObject(true);
     // TODO we'll want to do a lot more verification, either here, or
     // in a new verify method.
     if (buffer_obj && buffer_obj->type == BINDER_TYPE_PTR) {
+        if (buffer_handle != nullptr) {
+            *buffer_handle = 0; // TODO fix this
+        }
         return (void*)buffer_obj->buffer;
     }
 
     return nullptr;
 }
 
+const void* Parcel::readEmbeddedBuffer(uint64_t *buffer_handle, uint64_t /*parent_buffer_handle*/,
+                                       uint64_t /*parent_offset*/) const
+{
+    // TODO verify parent and offset
+    return (readBuffer(buffer_handle));
+}
+
+const native_handle_t* Parcel::readEmbeddedNativeHandle(uint64_t /*parent_buffer_handle*/,
+                                                        uint64_t /*parent_offset*/) const
+{
+    // TODO verify parent and offset, as well as fda object
+    return ((const native_handle_t*) readBuffer(nullptr));
+}
+
+const native_handle_t* Parcel::readNativeHandleNoDup() const
+{
+    native_handle_t *nat_handle = (native_handle_t*) readBuffer(nullptr);
+    if (nat_handle == nullptr) {
+        return nat_handle;
+    }
+    const binder_fd_array_object* fd_array_obj = (binder_fd_array_object*) readObject(true);
+    if (fd_array_obj && fd_array_obj->type == BINDER_TYPE_FDA) {
+        // TODO verification
+        return nat_handle;
+    }
+
+    return nullptr;
+}
+
 void Parcel::closeFileDescriptors()
 {
     size_t i = mObjectsSize;
@@ -2267,8 +2415,8 @@
     size_t i = mObjectsSize;
     while (i > 0) {
         i--;
-        const buffer_object* buffer
-            = reinterpret_cast<buffer_object*>(mData+mObjects[i]);
+        const binder_buffer_object* buffer
+            = reinterpret_cast<binder_buffer_object*>(mData+mObjects[i]);
         if (buffer->type == BINDER_TYPE_PTR) {
             dataSize += buffer->length;
         }
diff --git a/include/hwbinder/Parcel.h b/include/hwbinder/Parcel.h
index 8ce6fcc..87178ce 100644
--- a/include/hwbinder/Parcel.h
+++ b/include/hwbinder/Parcel.h
@@ -27,8 +27,48 @@
 #include <utils/String16.h>
 #include <utils/Vector.h>
 #include <utils/Flattenable.h>
+
 #include <linux/binder.h>
 
+enum {
+	BINDER_TYPE_PTR		= B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE),
+	BINDER_TYPE_FDA		= B_PACK_CHARS('f', 'd', 'a', B_TYPE_LARGE),
+};
+
+struct binder_transaction_data_sg {
+    binder_transaction_data    tr; /* regular transaction data */
+    binder_size_t              buffers_size; /* number of bytes of SG buffers */
+};
+
+struct binder_buffer_object {
+	__u32 type; /* MUST be BINDER_TYPE_PTR */
+	__u32 flags;
+
+	binder_uintptr_t	buffer; /* The buffer to copy */
+	binder_size_t		length; /* Length of the buffer to copy */
+	binder_size_t		parent; /* index of parent in objects */
+	binder_size_t		parent_offset; /* offset of pointer in parent */
+};
+
+struct binder_fd_array_object {
+	__u32 type; /* MUST be BINDER_TYPE_FDA */
+	__u32 flags;
+
+	binder_size_t       num_fds;
+	binder_size_t		parent; /* index of parent in objects */
+	binder_size_t		parent_offset; /* offset of pointer in parent */
+};
+
+enum {
+	BINDER_BUFFER_HAS_PARENT = 0x01,
+};
+
+enum {
+	BC_TRANSACTION_SG = _IOW('c', 17, struct binder_transaction_data_sg),
+	BC_REPLY_SG = _IOW('c', 18, struct binder_transaction_data_sg),
+};
+
+
 #include <hwbinder/IInterface.h>
 #include <hwbinder/Parcelable.h>
 
@@ -210,10 +250,16 @@
     status_t            writeDupImmutableBlobFileDescriptor(int fd);
 
     status_t            writeObject(const flat_binder_object& val, bool nullMetaData);
-    status_t            writeBufferObject(const buffer_object& val);
+    status_t            writeBufferObject(const binder_buffer_object& val);
+    status_t            writeFileDescriptorArrayObject(const binder_fd_array_object& val);
 
-    status_t            writeBuffer(void *buffer, size_t length, uint64_t *handle,
-                            uint64_t parent_handle = UINT64_MAX, uint32_t parent_offset = 0);
+    status_t            writeBuffer(void *buffer, size_t length, uint64_t *handle);
+    status_t            writeEmbeddedBuffer(void *buffer, size_t length, uint64_t *handle,
+                            uint64_t parent_buffer_handle, uint64_t parent_offset);
+
+    status_t            writeEmbeddedNativeHandle(const native_handle_t *handle,
+                            uint64_t parent_buffer_handle, uint64_t parent_offset);
+    status_t            writeNativeHandleNoDup(const native_handle* handle);
     // Like Parcel.java's writeNoException().  Just writes a zero int32.
     // Currently the native implementation doesn't do any of the StrictMode
     // stack gathering and serialization that the Java implementation does.
@@ -343,7 +389,12 @@
 
     const flat_binder_object* readObject(bool nullMetaData) const;
 
-    const void*         readBuffer() const;
+    const void*         readBuffer(uint64_t *buffer_handle) const;
+    const void*         readEmbeddedBuffer(uint64_t *buffer_handle,
+                           uint64_t parent_buffer_handle, uint64_t parent_offset) const;
+    const native_handle_t* readEmbeddedNativeHandle(uint64_t parent_buffer_handle,
+                           uint64_t parent_offset) const;
+    const native_handle_t* readNativeHandleNoDup() const;
     // Explicitly close all file descriptors in the parcel.
     void                closeFileDescriptors();