Implement duplicate buffer

Allow BufferClient to generate a opaque token in hidl_handle (i.e.
native_handle_t) format that could be used for IBufferHub::import.

The service will keep a mapping from token to client. Token comparison
is handled in BufferHubService.cpp, as it's opaque to the users.

Test: BufferHubBuffer_test (passed)
Bug: 118614157
Change-Id: Ie2b0b650dba90fe2ed2f8091dd88acb9768f261f
diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp
index b3662b2..37fd75f 100644
--- a/services/bufferhub/BufferClient.cpp
+++ b/services/bufferhub/BufferClient.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <bufferhub/BufferClient.h>
+#include <bufferhub/BufferHubService.h>
 #include <hidl/HidlSupport.h>
 
 namespace android {
@@ -26,9 +27,34 @@
 using hardware::hidl_handle;
 using hardware::Void;
 
+BufferClient* BufferClient::create(BufferHubService* service,
+                                   const std::shared_ptr<BufferNode>& node) {
+    if (!service) {
+        ALOGE("%s: service cannot be nullptr.", __FUNCTION__);
+        return nullptr;
+    } else if (!node) {
+        ALOGE("%s: node cannot be nullptr.", __FUNCTION__);
+        return nullptr;
+    }
+    return new BufferClient(service, node);
+}
+
 Return<void> BufferClient::duplicate(duplicate_cb _hidl_cb) {
-    // TODO(b/118614157): implement token generation and registration
-    _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::NO_ERROR);
+    if (!mBufferNode) {
+        // Should never happen
+        ALOGE("%s: node is missing.", __FUNCTION__);
+        _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::BUFFER_FREED);
+        return Void();
+    }
+
+    sp<BufferHubService> service = mService.promote();
+    if (service == nullptr) {
+        // Should never happen. Kill the process.
+        LOG_FATAL("%s: service died.", __FUNCTION__);
+    }
+
+    const hidl_handle token = service->registerToken(this);
+    _hidl_cb(/*token=*/token, /*status=*/BufferHubStatus::NO_ERROR);
     return Void();
 }