Pointer support and embedded types in HIDL.

Bug: 31300815
Bug: 31349114

Test: `mma`
Test: `make hidl_test && adb sync && adb shell hidl_test`
      Only works with a kernel patch.

Change-Id: I046948afdfe08f57db5f31f333217580ae64f5b0
diff --git a/include/hidl/HidlSupport.h b/include/hidl/HidlSupport.h
index e4409e4..760c7ab 100644
--- a/include/hidl/HidlSupport.h
+++ b/include/hidl/HidlSupport.h
@@ -160,6 +160,11 @@
             size_t parentOffset,
             size_t *handle) const;
 
+    status_t findInParcel(const Parcel &parcel, size_t *handle) const {
+        return parcel.quickFindBuffer(mBuffer, handle);
+    }
+
+
 private:
     T *mBuffer;
     size_t mSize;
@@ -320,6 +325,127 @@
             parentOffset + offsetof(hidl_vec<T>, mBuffer));
 }
 
+///////////////////////////// pointers for HIDL
+
+template <typename T>
+static status_t readEmbeddedReferenceFromParcel(
+        T const* * /* bufptr */,
+        const Parcel & parcel,
+        size_t parentHandle,
+        size_t parentOffset,
+        size_t *handle,
+        bool *shouldResolveRefInBuffer
+    ) {
+    // *bufptr is ignored because, if I am embedded in some
+    // other buffer, the kernel should have fixed me up already.
+    bool isPreviouslyWritten;
+    status_t result = parcel.readEmbeddedReference(
+        nullptr, // ignored, not written to bufptr.
+        handle,
+        parentHandle,
+        parentOffset,
+        &isPreviouslyWritten);
+    // tell caller to run T::readEmbeddedToParcel and
+    // T::readEmbeddedReferenceToParcel if necessary.
+    // It is not called here because we don't know if these two are valid methods.
+    *shouldResolveRefInBuffer = !isPreviouslyWritten;
+    return result;
+}
+
+template <typename T>
+static status_t writeEmbeddedReferenceToParcel(
+        T const* buf,
+        Parcel *parcel, size_t parentHandle, size_t parentOffset,
+        size_t *handle,
+        bool *shouldResolveRefInBuffer
+        ) {
+
+    if(buf == nullptr) {
+        *shouldResolveRefInBuffer = false;
+        return parcel->writeEmbeddedNullReference(handle, parentHandle, parentOffset);
+    }
+
+    // find whether the buffer exists
+    size_t childHandle, childOffset;
+    status_t result;
+    bool found;
+
+    result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset);
+
+    // tell caller to run T::writeEmbeddedToParcel and
+    // T::writeEmbeddedReferenceToParcel if necessary.
+    // It is not called here because we don't know if these two are valid methods.
+    *shouldResolveRefInBuffer = !found;
+
+    if(result != OK) {
+        return result; // bad pointers and length given
+    }
+    if(!found) { // did not find it.
+        return parcel->writeEmbeddedBuffer(buf, sizeof(T), handle,
+                parentHandle, parentOffset);
+    }
+    // found the buffer. easy case.
+    return parcel->writeEmbeddedReference(
+            handle,
+            childHandle,
+            childOffset,
+            parentHandle,
+            parentOffset);
+}
+
+template <typename T>
+static status_t readReferenceFromParcel(
+        T const* *bufptr,
+        const Parcel & parcel,
+        size_t *handle,
+        bool *shouldResolveRefInBuffer
+    ) {
+    bool isPreviouslyWritten;
+    status_t result = parcel.readReference(reinterpret_cast<void const* *>(bufptr),
+            handle, &isPreviouslyWritten);
+    // tell caller to run T::readEmbeddedToParcel and
+    // T::readEmbeddedReferenceToParcel if necessary.
+    // It is not called here because we don't know if these two are valid methods.
+    *shouldResolveRefInBuffer = !isPreviouslyWritten;
+    return result;
+}
+
+template <typename T>
+static status_t writeReferenceToParcel(
+        T const *buf,
+        Parcel * parcel,
+        size_t *handle,
+        bool *shouldResolveRefInBuffer
+    ) {
+
+    if(buf == nullptr) {
+        *shouldResolveRefInBuffer = false;
+        return parcel->writeNullReference(handle);
+    }
+
+    // find whether the buffer exists
+    size_t childHandle, childOffset;
+    status_t result;
+    bool found;
+
+    result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset);
+
+    // tell caller to run T::writeEmbeddedToParcel and
+    // T::writeEmbeddedReferenceToParcel if necessary.
+    // It is not called here because we don't know if these two are valid methods.
+    *shouldResolveRefInBuffer = !found;
+
+    if(result != OK) {
+        return result; // bad pointers and length given
+    }
+    if(!found) { // did not find it.
+        return parcel->writeBuffer(buf, sizeof(T), handle);
+    }
+    // found the buffer. easy case.
+    return parcel->writeReference(handle,
+        childHandle, childOffset);
+}
+
 // ----------------------------------------------------------------------
 // Version functions
 struct hidl_version {