[ddk][api] Add API to get length of device metadata
This patch adds a new method (device_get_metadata_size) to the DDK API, which allows
the retrieval of the size of a given metadata key on a device.
Test: runtests -t driver-test
Change-Id: Ib2535b17e3e2b6b9bc225835d6ac27e288aadd52
diff --git a/system/core/devmgr/devhost/api.cpp b/system/core/devmgr/devhost/api.cpp
index e1475a4..dcc5ede 100644
--- a/system/core/devmgr/devhost/api.cpp
+++ b/system/core/devmgr/devhost/api.cpp
@@ -237,6 +237,13 @@
return devhost_get_metadata(dev_ref, type, buf, buflen, actual);
}
+__EXPORT zx_status_t device_get_metadata_size(zx_device_t* dev, uint32_t type,
+ size_t* out_size) {
+ ApiAutoLock lock;
+ auto dev_ref = fbl::WrapRefPtr(dev);
+ return devhost_get_metadata_size(dev_ref, type, out_size);
+}
+
__EXPORT zx_status_t device_add_metadata(zx_device_t* dev, uint32_t type,
const void* data, size_t length) {
ApiAutoLock lock;
diff --git a/system/core/devmgr/devhost/devhost.cpp b/system/core/devmgr/devhost/devhost.cpp
index f7e44db..7eed1eb 100644
--- a/system/core/devmgr/devhost/devhost.cpp
+++ b/system/core/devmgr/devhost/devhost.cpp
@@ -1117,6 +1117,30 @@
return ZX_OK;
}
+zx_status_t devhost_get_metadata_size(const fbl::RefPtr<zx_device_t>& dev, uint32_t type,
+ size_t* out_length) {
+
+ const zx::channel& rpc = *dev->rpc;
+ if (!rpc.is_valid()) {
+ return ZX_ERR_IO_REFUSED;
+ }
+ log_rpc(dev, "get-metadata");
+ zx_status_t call_status;
+ zx_status_t status = fuchsia_device_manager_CoordinatorGetMetadataSize(
+ rpc.get(), type, &call_status, out_length);
+ if (status != ZX_OK) {
+ log(ERROR, "devhost: rpc:get-metadata sending failed: %d\n", status);
+ return status;
+ }
+ if (call_status != ZX_OK) {
+ if (call_status != ZX_ERR_NOT_FOUND) {
+ log(ERROR, "devhost: rpc:get-metadata failed: %d\n", call_status);
+ }
+ return call_status;
+ }
+ return ZX_OK;
+}
+
zx_status_t devhost_add_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type,
const void* data, size_t length) {
if (!data && length) {
diff --git a/system/core/devmgr/devhost/devhost.h b/system/core/devmgr/devhost/devhost.h
index 8731f3d..6eb5c5b 100644
--- a/system/core/devmgr/devhost/devhost.h
+++ b/system/core/devmgr/devhost/devhost.h
@@ -175,6 +175,9 @@
zx_status_t devhost_get_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type, void* buf,
size_t buflen, size_t* actual) REQ_DM_LOCK;
+zx_status_t devhost_get_metadata_size(const fbl::RefPtr<zx_device_t>& dev, uint32_t type,
+ size_t* size) REQ_DM_LOCK;
+
zx_status_t devhost_add_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type,
const void* data, size_t length) REQ_DM_LOCK;
diff --git a/system/core/devmgr/devmgr/coordinator.cpp b/system/core/devmgr/devmgr/coordinator.cpp
index cdaad7c..c70e3d7 100644
--- a/system/core/devmgr/devmgr/coordinator.cpp
+++ b/system/core/devmgr/devmgr/coordinator.cpp
@@ -1122,6 +1122,37 @@
return ZX_ERR_NOT_FOUND;
}
+zx_status_t Coordinator::GetMetadataSize(Device* dev, uint32_t type, size_t* size) {
+ // search dev and its parent devices for a match
+ Device* test = dev;
+ while (test) {
+ for (const auto& md : test->metadata) {
+ if (md.type == type) {
+ *size = md.length;
+ return ZX_OK;
+ }
+ }
+ test = test->parent;
+ }
+
+ // if no metadata is found, check list of metadata added via device_publish_metadata()
+ char path[fuchsia_device_manager_PATH_MAX];
+ zx_status_t status = GetTopoPath(dev, path, sizeof(path));
+ if (status != ZX_OK) {
+ return status;
+ }
+
+ for (const auto& md : published_metadata_) {
+ const char* md_path = md.Data() + md.length;
+ if (md.type == type && path_is_child(md_path, path)) {
+ *size = md.length;
+ return ZX_OK;
+ }
+ }
+
+ return ZX_ERR_NOT_FOUND;
+}
+
zx_status_t Coordinator::AddMetadata(Device* dev, uint32_t type, const void* data,
uint32_t length) {
fbl::unique_ptr<Metadata> md;
@@ -1303,6 +1334,16 @@
return fuchsia_device_manager_CoordinatorGetMetadata_reply(txn, status, data, actual);
}
+static zx_status_t fidl_GetMetadataSize(void* ctx, uint32_t key, fidl_txn_t* txn) {
+ auto dev = static_cast<Device*>(ctx);
+ size_t size;
+ zx_status_t status = dev->coordinator->GetMetadataSize(dev, key, &size);
+ if (status != ZX_OK) {
+ return fuchsia_device_manager_CoordinatorGetMetadataSize_reply(txn, status, 0);
+ }
+ return fuchsia_device_manager_CoordinatorGetMetadataSize_reply(txn, status, size);
+}
+
static zx_status_t fidl_AddMetadata(void* ctx, uint32_t key,
const uint8_t* data_data, size_t data_count, fidl_txn_t* txn) {
static_assert(fuchsia_device_manager_METADATA_MAX <= UINT32_MAX);
@@ -1440,6 +1481,7 @@
.GetTopologicalPath = fidl_GetTopologicalPath,
.LoadFirmware = fidl_LoadFirmware,
.GetMetadata = fidl_GetMetadata,
+ .GetMetadataSize = fidl_GetMetadataSize,
.AddMetadata = fidl_AddMetadata,
.PublishMetadata = fidl_PublishMetadata,
.DmCommand = fidl_DmCommand,
diff --git a/system/core/devmgr/devmgr/coordinator.h b/system/core/devmgr/devmgr/coordinator.h
index 1b42a4b..239d868 100644
--- a/system/core/devmgr/devmgr/coordinator.h
+++ b/system/core/devmgr/devmgr/coordinator.h
@@ -328,6 +328,7 @@
zx_status_t GetMetadata(Device* dev, uint32_t type, void* buffer, size_t buflen,
size_t* actual);
+ zx_status_t GetMetadataSize(Device* dev, uint32_t type, size_t* size);
zx_status_t AddMetadata(Device* dev, uint32_t type, const void* data, uint32_t length);
zx_status_t PublishMetadata(Device* dev, const char* path, uint32_t type, const void* data,
uint32_t length);
diff --git a/system/dev/test/ddk-test/metadata-test.c b/system/dev/test/ddk-test/metadata-test.c
index 2cec219..efa65cf 100644
--- a/system/dev/test/ddk-test/metadata-test.c
+++ b/system/dev/test/ddk-test/metadata-test.c
@@ -20,9 +20,14 @@
status = device_get_metadata(ddk_test_dev, 1, buffer,sizeof(buffer), &actual);
ASSERT_EQ(status, ZX_ERR_NOT_FOUND, "device_get_metadata did not return ZX_ERR_NOT_FOUND");
+ status = device_get_metadata_size(ddk_test_dev, 1, &actual);
+ ASSERT_EQ(status, ZX_ERR_NOT_FOUND, "device_get_metadata_size should return ZX_ERR_NOT_FOUND");
+
status = device_add_metadata(ddk_test_dev, 1, TEST_STRING, strlen(TEST_STRING) + 1);
ASSERT_EQ(status, ZX_OK, "device_add_metadata failed");
+ status = device_get_metadata_size(ddk_test_dev, 1, &actual);
+ ASSERT_EQ(strlen(TEST_STRING)+1, actual, "Incorrect output length was returned.");
status = device_get_metadata(ddk_test_dev, 1, buffer, sizeof(buffer), &actual);
ASSERT_EQ(status, ZX_OK, "device_get_metadata failed");
ASSERT_EQ(actual, strlen(TEST_STRING) + 1, "");
diff --git a/system/fidl/fuchsia-device-manager/coordinator.fidl b/system/fidl/fuchsia-device-manager/coordinator.fidl
index 227b0a6..d31df50 100644
--- a/system/fidl/fuchsia-device-manager/coordinator.fidl
+++ b/system/fidl/fuchsia-device-manager/coordinator.fidl
@@ -128,6 +128,10 @@
0x10000018: GetMetadata(uint32 key)
-> (zx.status status, vector<uint8>:METADATA_MAX? data);
+ /// Retrieve the metadata size associated with this device and the given key.
+ GetMetadataSize(uint32 key)
+ -> (zx.status status, uint64 size);
+
/// Add metadata blob associated with this device and the given key.
/// TODO(teisenbe): Document the behavior of calling this twice with the same
/// key. I believe the current behavior results in inaccessible data that is
diff --git a/system/ulib/ddk/include/ddk/device.h b/system/ulib/ddk/include/ddk/device.h
index e0115bb..0e0a9e7 100644
--- a/system/ulib/ddk/include/ddk/device.h
+++ b/system/ulib/ddk/include/ddk/device.h
@@ -264,6 +264,10 @@
zx_status_t device_get_metadata(zx_device_t* dev, uint32_t type, void* buf, size_t buflen,
size_t* actual);
+// retrieves metadata size for a specific device
+// searches parent devices to find a match
+zx_status_t device_get_metadata_size(zx_device_t* dev, uint32_t type, size_t* out_size);
+
// Adds metadata to a specific device.
zx_status_t device_add_metadata(zx_device_t* dev, uint32_t type, const void* data, size_t length);