[sysmem] sysmem-connector zircon service Make fuchsia_sysmem_Allocator2 a zircon service. The service finds a sysmem device instance and forwards the service request to the driver to be served directly from there. This way a non-driver client of sysmem doesn't need to hassle with finding the sysmem device instance etc. A similar garnet service will be added which shares the sysmem-connector code, so to anticipate that, sysmem-connector is a ulib. Tested: /system/test/sys/sysmem-test Change-Id: Ie2773eb919b67a5bc53bd0a4e8b50921e33127fc
diff --git a/system/core/devmgr/devmgr/main.cpp b/system/core/devmgr/devmgr/main.cpp index f5d9786..66cf73f 100644 --- a/system/core/devmgr/devmgr/main.cpp +++ b/system/core/devmgr/devmgr/main.cpp
@@ -409,6 +409,21 @@ // services such as crashsvc and the profile service. launchpad_add_handle(lp, root_job_copy.release(), PA_HND(PA_USER0, 1)); + // Give svchost access to /dev/class/sysmem, to enable svchost to forward sysmem service + // requests to the sysmem driver. Create a namespace containing /dev/class/sysmem. + const char* nametable[1] = {}; + uint32_t count = 0; + zx::channel fs_handle = devmgr::fs_clone("dev/class/sysmem"); + if (fs_handle.is_valid()) { + nametable[count] = "/sysmem"; + launchpad_add_handle(lp, fs_handle.release(), PA_HND(PA_NS_DIR, count++)); + } else { + launchpad_abort(lp, ZX_ERR_BAD_STATE, "devmgr: failed to clone /dev/class/sysmem"); + // The launchpad_go() call below will fail, but will still free lp. + } + + launchpad_set_nametable(lp, count, nametable); + const char* errmsg = nullptr; if ((status = launchpad_go(lp, nullptr, &errmsg)) < 0) { printf("devmgr: launchpad %s (%s) failed: %s: %d\n",
diff --git a/system/core/svchost/rules.mk b/system/core/svchost/rules.mk index e86a513..7c414bc 100644 --- a/system/core/svchost/rules.mk +++ b/system/core/svchost/rules.mk
@@ -11,6 +11,7 @@ MODULE_SRCS += \ $(LOCAL_DIR)/svchost.cpp \ + $(LOCAL_DIR)/sysmem.cpp \ $(LOCAL_DIR)/crashsvc.cpp MODULE_FIDL_LIBS := \ @@ -29,6 +30,7 @@ system/ulib/svc \ system/ulib/process-launcher \ system/ulib/sysmem \ + system/ulib/sysmem-connector \ system/ulib/fs \ system/ulib/async \ system/ulib/async.cpp \
diff --git a/system/core/svchost/svchost.cpp b/system/core/svchost/svchost.cpp index 53f7726..4fc8bfa 100644 --- a/system/core/svchost/svchost.cpp +++ b/system/core/svchost/svchost.cpp
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "sysmem.h" + #include <fbl/algorithm.h> #include <lib/async-loop/cpp/loop.h> #include <lib/fdio/util.h> @@ -172,6 +174,7 @@ zx_service_provider_instance_t service_providers[] = { {.provider = launcher_get_service_provider(), .ctx = nullptr}, {.provider = sysmem_get_service_provider(), .ctx = nullptr}, + {.provider = sysmem2_get_service_provider(), .ctx = nullptr}, {.provider = profile_get_service_provider(), .ctx = reinterpret_cast<void*>(static_cast<uintptr_t>(profile_root_job_copy))}, }; @@ -185,7 +188,6 @@ } } - // if full system is not required drop simple logger service. zx_service_provider_instance_t logger_service{.provider = logger_get_service_provider(), .ctx = nullptr};
diff --git a/system/core/svchost/sysmem.cpp b/system/core/svchost/sysmem.cpp new file mode 100644 index 0000000..4410978 --- /dev/null +++ b/system/core/svchost/sysmem.cpp
@@ -0,0 +1,54 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sysmem.h" + +#include <fuchsia/sysmem/c/fidl.h> +#include <lib/sysmem-connector/sysmem-connector.h> +#include <lib/zx/channel.h> + +#include <cstring> + +const char *kSysmemSvchostPath = "/sysmem"; + +// We don't really need a service context, only a sysmem-connector context, so +// we just directly use the sysmem-connector context as the only context. +static zx_status_t sysmem2_init(void** out_ctx) { + return sysmem_connector_init(kSysmemSvchostPath, reinterpret_cast<sysmem_connector_t**>(out_ctx)); +} + +static zx_status_t sysmem2_connect( + void* ctx, async_dispatcher_t* dispatcher, const char* service_name, + zx_handle_t allocator2_request_param) { + zx::channel allocator2_request(allocator2_request_param); + sysmem_connector_t* connector = static_cast<sysmem_connector_t*>(ctx); + if (!strcmp(service_name, fuchsia_sysmem_Allocator2_Name)) { + sysmem_connector_queue_connection_request(connector, allocator2_request.release()); + } + return ZX_ERR_NOT_SUPPORTED; +} +static void sysmem2_release(void* ctx) { + sysmem_connector_release(static_cast<sysmem_connector_t*>(ctx)); +} + +static constexpr const char* sysmem2_services[] = { + fuchsia_sysmem_Allocator2_Name, + nullptr, +}; + +static constexpr zx_service_ops_t sysmem2_ops = { + .init = sysmem2_init, + .connect = sysmem2_connect, + .release = sysmem2_release, +}; + +static constexpr zx_service_provider_t sysmem2_service_provider = { + .version = SERVICE_PROVIDER_VERSION, + .services = sysmem2_services, + .ops = &sysmem2_ops, +}; + +const zx_service_provider_t* sysmem2_get_service_provider() { + return &sysmem2_service_provider; +}
diff --git a/system/core/svchost/sysmem.h b/system/core/svchost/sysmem.h new file mode 100644 index 0000000..ce97106 --- /dev/null +++ b/system/core/svchost/sysmem.h
@@ -0,0 +1,9 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include <lib/svc/service.h> + +const zx_service_provider_t* sysmem2_get_service_provider();
diff --git a/system/ulib/sysmem-connector/include/lib/sysmem-connector/sysmem-connector.h b/system/ulib/sysmem-connector/include/lib/sysmem-connector/sysmem-connector.h new file mode 100644 index 0000000..5c4bfc1 --- /dev/null +++ b/system/ulib/sysmem-connector/include/lib/sysmem-connector/sysmem-connector.h
@@ -0,0 +1,41 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include <zircon/compiler.h> +#include <zircon/types.h> + +__BEGIN_CDECLS + +// The client of sysmem-connector shouldn't need to know how large this struct +// is (or even whether the pointer is to a heap allocation vs. within a heap +// allocation), so it's declared here, but defined in sysmem-connector.cpp. +typedef struct sysmem_connector sysmem_connector_t; + +// Allocate and initialize a sysmem_connector_t. ZX_OK from this function +// doesn't guarantee that the sysmem driver is found yet, only that the +// connector has successfully been created and initialized. +// +// |sysmem_device_path| must remain valid for lifetime of sysmem_connector_t. +// This is the path to the directory of sysmem device instances (just one +// device instance will actually exist, unless something is going wrong). +zx_status_t sysmem_connector_init(const char* sysmem_directory_path, sysmem_connector_t** out_connector); + +// allocator2_request is consumed. A call to this function doesn't guarantee +// that the request will reach the sysmem driver, only that the connector has +// queued the request internally to be sent. +// +// If the sysmem driver can't be contacted for an extended duration, the request +// may sit in the queue for that duration - there isn't a timeout, because that +// would probably do more harm than good, since sysmem is always supposed to be +// running. +void sysmem_connector_queue_connection_request( + sysmem_connector_t* connector, + zx_handle_t allocator2_request); + +// This call is not allowed to fail. +void sysmem_connector_release(sysmem_connector_t* connector); + +__END_CDECLS
diff --git a/system/ulib/sysmem-connector/rules.mk b/system/ulib/sysmem-connector/rules.mk new file mode 100644 index 0000000..8e4bf9d --- /dev/null +++ b/system/ulib/sysmem-connector/rules.mk
@@ -0,0 +1,30 @@ +# Copyright 2019 The Fuchsia Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_TYPE := userlib + +MODULE_SRCS := \ + $(LOCAL_DIR)/sysmem-connector.cpp \ + +MODULE_COMPILEFLAGS += -fvisibility=hidden + +MODULE_FIDL_LIBS := \ + system/fidl/fuchsia-sysmem + +MODULE_STATIC_LIBS := \ + system/ulib/async \ + system/ulib/async-loop \ + system/ulib/async-loop.cpp \ + system/ulib/fbl \ + system/ulib/fzl \ + system/ulib/zx \ + +MODULE_LIBS := \ + system/ulib/fdio \ + +include make/module.mk
diff --git a/system/ulib/sysmem-connector/sysmem-connector.cpp b/system/ulib/sysmem-connector/sysmem-connector.cpp new file mode 100644 index 0000000..bb6ce7a --- /dev/null +++ b/system/ulib/sysmem-connector/sysmem-connector.cpp
@@ -0,0 +1,318 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <lib/sysmem-connector/sysmem-connector.h> + +#include <fbl/auto_lock.h> +#include <fbl/function.h> +#include <fbl/mutex.h> +#include <fbl/unique_fd.h> +#include <fuchsia/sysmem/c/fidl.h> +#include <lib/async/cpp/task.h> +#include <lib/async-loop/cpp/loop.h> +#include <lib/fdio/watcher.h> +#include <lib/fdio/util.h> +#include <lib/fzl/fdio.h> +#include <lib/zx/channel.h> + +#include <fcntl.h> +#include <errno.h> +#include <queue> +#include <threads.h> + +// The actual sysmem FIDL server is in the sysmem driver. The code that watches +// for the driver and sends sysmem service requests to the driver is in +// ulib/sysmem-connector. The code here just needs to queue requests to +// sysmem-connector. + +// Clients interact with sysmem-connector using a C ABI, but we want to use C++ +// for the implementation. We have SysmemConnector inherit from an empty +// sysmem_connector struct just to make the SysmemConnector class officially be +// a class not a struct, and to make the SysmemConnector name consistent with +// C++ coding conventions, and have member names with "_" at the end consistent +// with coding conventions, etc. +// +// Every instance of sysmem_connector is actually a SysmemConnector and vice +// versa. +struct sysmem_connector { + // Intentionally declared as empty; never instantiated; see SysmemConnector. +}; +class SysmemConnector : public sysmem_connector { + // public in this case just means public to this file. The interface is via + // the functions declared in lib/sysmem-connector/sysmem-connector.h. + public: + SysmemConnector(const char* sysmem_device_path); + zx_status_t Start(); + void QueueRequest(zx::channel allocator2_request); + void Stop(); + private: + void Post(fbl::Closure to_run); + + static zx_status_t DeviceAddedShim(int dirfd, int event, const char* fn, void* cookie); + zx_status_t DeviceAdded(int dirfd, int event, const char* fn); + + zx_status_t ConnectToSysmemDriver(); + + void ProcessQueue(); + + // + // Set once during construction + Start(), never set again. + // + + const char* sysmem_device_path_{}; + async::Loop process_queue_loop_; + thrd_t process_queue_thrd_{}; + + // + // Only touched from process_queue_loop_'s one thread. + // + + fbl::unique_fd sysmem_dir_fd_; + zx::channel driver_connector_client_; + + // + // Synchronized using lock_. + // + + fbl::Mutex lock_; + std::queue<zx::channel> connection_requests_ __TA_GUARDED(lock_); +}; + +SysmemConnector::SysmemConnector(const char* sysmem_device_path) + : sysmem_device_path_(sysmem_device_path), + process_queue_loop_(&kAsyncLoopConfigNoAttachToThread) { + ZX_DEBUG_ASSERT(sysmem_device_path_); +} + +zx_status_t SysmemConnector::Start() { + ZX_DEBUG_ASSERT(!sysmem_dir_fd_); + { + int fd = open(sysmem_device_path_, O_DIRECTORY | O_RDONLY); + if (fd < 0) { + printf("sysmem-connector: Failed to open %s: %d\n", sysmem_device_path_, errno); + return ZX_ERR_INTERNAL; + } + sysmem_dir_fd_.reset(fd); + } + ZX_DEBUG_ASSERT(sysmem_dir_fd_); + + // The process_queue_thrd_ is filled out before any code that checks it runs on the thread, because the current + // thread is the only thread that triggers anything to happen on the thread being created here, and that is only + // done after process_queue_thrd_ is filled out by the current thread. + zx_status_t status = process_queue_loop_.StartThread("SysmemConnector-ProcessQueue", &process_queue_thrd_); + if (status != ZX_OK) { + printf("sysmem-connector: process_queue_loop_.StartThread() failed - status: %d\n", status); + return status; + } + // Establish initial connection to sysmem driver async. + Post([this]{ConnectToSysmemDriver();}); + return ZX_OK; +} + +void SysmemConnector::QueueRequest(zx::channel allocator2_request) { + ZX_DEBUG_ASSERT(thrd_current() != process_queue_thrd_); + bool trigger_needed; + { // scope lock + fbl::AutoLock lock(&lock_); + trigger_needed = connection_requests_.empty(); + connection_requests_.emplace(std::move(allocator2_request)); + } // ~lock + if (trigger_needed) { + Post([this]{ProcessQueue();}); + } +} + +void SysmemConnector::Stop() { + ZX_DEBUG_ASSERT(thrd_current() != process_queue_thrd_); + process_queue_loop_.Quit(); + process_queue_loop_.JoinThreads(); + process_queue_loop_.Shutdown(); +} + +void SysmemConnector::Post(fbl::Closure to_run) { + zx_status_t post_status = async::PostTask( + process_queue_loop_.dispatcher(), std::move(to_run)); + // We don't expect this post to ever fail. + ZX_ASSERT(post_status == ZX_OK); +} + +zx_status_t SysmemConnector::DeviceAddedShim(int dirfd, int event, const char* fn, void* cookie) { + ZX_DEBUG_ASSERT(cookie); + SysmemConnector* connector = static_cast<SysmemConnector*>(cookie); + return connector->DeviceAdded(dirfd, event, fn); +} + +zx_status_t SysmemConnector::DeviceAdded(int dirfd, int event, const char* filename) { + ZX_DEBUG_ASSERT(thrd_current() == process_queue_thrd_); + if (event != WATCH_EVENT_ADD_FILE) { + // Keep going on IDLE or REMOVE. There's nothing else useful that the + // current thread can do until a sysmem device instance is available, + // and we don't have any reason to attempt to directly handle any + // REMOVE(s) since we'll do fdio_watch_directory() again later from + // scratch instead. + return ZX_OK; + } + ZX_DEBUG_ASSERT(event == WATCH_EVENT_ADD_FILE); + + zx::channel driver_connector_client; + zx::channel driver_connector_server; + zx_status_t status = zx::channel::create(0, &driver_connector_client, &driver_connector_server); + if (status != ZX_OK) { + printf("SysmemConnector::DeviceAdded() zx::channel::create() failed - status: %d\n", status); + ZX_DEBUG_ASSERT(status != ZX_ERR_STOP); + // If channel create fails, give up on this attempt to find a sysmem + // device instance. If another request arrives later, we'll try again + // later. + return status; + } + + // We don't intend to close dirfd; all paths should release not close. + fbl::unique_fd unique_dirfd(dirfd); + fzl::FdioCaller caller(std::move(unique_dirfd)); + status = fdio_service_connect_at(caller.borrow_channel(), filename, driver_connector_server.release()); + // Never close dirfd. + caller.release().release(); + if (status != ZX_OK) { + printf("SysmemConnector::DeviceAdded() fdio_service_connect_at() failed - status: %d\n", status); + ZX_DEBUG_ASSERT(status != ZX_ERR_STOP); + // If somehow fdio_service_connect_at() fails for this device instance, + // keep watching for another device instance. + return ZX_OK; + } + + driver_connector_client_ = std::move(driver_connector_client); + ZX_DEBUG_ASSERT(driver_connector_client_); + return ZX_ERR_STOP; +} + +zx_status_t SysmemConnector::ConnectToSysmemDriver() { + ZX_DEBUG_ASSERT(thrd_current() == process_queue_thrd_); + ZX_DEBUG_ASSERT(!driver_connector_client_); + // Returns ZX_ERR_STOP as soon as one of the 000, 001 device instances is + // found. We rely on those to go away if the corresponding sysmem instance + // is no longer operational, so that we don't find them when we call + // ConnectToSysmemDriver() again upon discovering that we can't send to a + // previous device instance. + // + // TODO(dustingreen): Currently if this watch never finds a sysmem device + // instance, then sysmem_connector_release() will block forever. This can + // be fixed once it's feasible to use DeviceWatcher (or similar) here + // instead (currently DeviceWatcher is in garnet not zircon). + zx_status_t watch_status = fdio_watch_directory( + sysmem_dir_fd_.get(), DeviceAddedShim, ZX_TIME_INFINITE, this); + if (watch_status != ZX_ERR_STOP) { + printf("sysmem-connector: Failed to find sysmem device - status: %d\n", watch_status); + return watch_status; + } + ZX_DEBUG_ASSERT(driver_connector_client_); + return ZX_OK; +} + +void SysmemConnector::ProcessQueue() { + ZX_DEBUG_ASSERT(thrd_current() == process_queue_thrd_); + while (true) { + zx::channel allocator2_request; + { // scope lock + fbl::AutoLock lock(&lock_); + if (connection_requests_.empty()) { + return; + } + allocator2_request = std::move(connection_requests_.front()); + connection_requests_.pop(); + } // ~lock + ZX_DEBUG_ASSERT(allocator2_request); + + // Poll for PEER_CLOSED just before we need the channel to be usable, to + // avoid routing a request to a stale no-longer-usable sysmem device + // instance. This doesn't eliminate the inherent race where a request + // can be sent to an instance that's already started failing - that race + // is fine. This check is just a best-effort way to avoid routing to a + // super-stale previous instance. + // + // TODO(dustingreen): When it becomes more convenient, switch to + // noticing PEER_CLOSED async. Currently it doesn't seem particularly + // safe to use sysmem_fdio_caller_.borrow_channel() to borrow for an + // async wait. + if (driver_connector_client_) { + zx_signals_t observed; + zx_status_t wait_status = zx_object_wait_one( + driver_connector_client_.get(), + ZX_CHANNEL_PEER_CLOSED, + ZX_TIME_INFINITE_PAST, + &observed); + if (wait_status == ZX_OK) { + ZX_DEBUG_ASSERT(observed & ZX_CHANNEL_PEER_CLOSED); + // This way, we'll call ConnectToSysmemDriver() below. + driver_connector_client_.reset(); + } else { + // Any other failing status is unexpected. + ZX_DEBUG_ASSERT(ZX_ERR_TIMED_OUT); + } + } + + if (!driver_connector_client_) { + zx_status_t connect_status = ConnectToSysmemDriver(); + if (connect_status != ZX_OK) { + // ~allocator2_request - we'll try again to connect to a sysmem + // instance next time a request comes in, but any given request + // gets a max of one attempt to connect to a sysmem device + // instance, in case attempts to find a sysmem device instance + // are just failing. + return; + } + } + ZX_DEBUG_ASSERT(driver_connector_client_); + + zx_status_t send_connect_status = fuchsia_sysmem_DriverConnectorConnect( + driver_connector_client_.get(), allocator2_request.release()); + if (send_connect_status != ZX_OK) { + // The most likely failing send_connect_status is + // ZX_ERR_PEER_CLOSED, which can happen if the channel closed since + // we checked above. Since we don't really expect even + // ZX_ERR_PEER_CLOSED unless sysmem is having problems, complain + // about the error regardless of which error. + printf("SysmemConnector::ProcessQueue() DriverConnectorConnect() returned unexpected status: %d\n", + send_connect_status); + + // Regardless of the specific error, we want to try + // ConnectToSysmemDriver() again for the _next_ request. + driver_connector_client_.reset(); + + // We don't retry this request (the window for getting + // ZX_ERR_PEER_CLOSED is short due to check above, and exists in any + // case due to possibility of close from other end at any time), but + // the next request will try ConnectToSysmemDriver() again. + // + // continue with next request + } + } +} + +zx_status_t sysmem_connector_init(const char* sysmem_device_path, sysmem_connector_t** out_connector) { + SysmemConnector* connector = new SysmemConnector(sysmem_device_path); + zx_status_t status = connector->Start(); + if (status != ZX_OK) { + printf("sysmem_connector_init() connector->Start() failed - status: %d\n", status); + return status; + } + *out_connector = connector; + return ZX_OK; +} + +void sysmem_connector_queue_connection_request( + sysmem_connector_t* connector_param, + zx_handle_t allocator2_request_param) { + zx::channel allocator2_request(allocator2_request_param); + ZX_DEBUG_ASSERT(connector_param); + ZX_DEBUG_ASSERT(allocator2_request); + SysmemConnector* connector = static_cast<SysmemConnector*>(connector_param); + connector->QueueRequest(std::move(allocator2_request)); +} + +void sysmem_connector_release(sysmem_connector_t* connector_param) { + ZX_DEBUG_ASSERT(connector_param); + SysmemConnector* connector = static_cast<SysmemConnector*>(connector_param); + connector->Stop(); + delete connector; +}
diff --git a/system/ulib/sysmem/rules.mk b/system/ulib/sysmem/rules.mk index a758f97..22f12e1 100644 --- a/system/ulib/sysmem/rules.mk +++ b/system/ulib/sysmem/rules.mk
@@ -9,7 +9,7 @@ MODULE_TYPE := userlib MODULE_SRCS := \ - $(LOCAL_DIR)/sysmem.cpp + $(LOCAL_DIR)/sysmem.cpp \ MODULE_COMPILEFLAGS += -fvisibility=hidden
diff --git a/system/utest/sysmem/sysmem_tests.cpp b/system/utest/sysmem/sysmem_tests.cpp index ab753d0..df01ab9 100644 --- a/system/utest/sysmem/sysmem_tests.cpp +++ b/system/utest/sysmem/sysmem_tests.cpp
@@ -47,6 +47,21 @@ return ZX_OK; } +zx_status_t connect_to_sysmem_service(zx::channel* allocator2_client_param) { + zx_status_t status; + + zx::channel allocator2_client; + zx::channel allocator2_server; + status = zx::channel::create(0, &allocator2_client, &allocator2_server); + ASSERT_EQ(status, ZX_OK, ""); + + status = fdio_service_connect("/svc/fuchsia.sysmem.Allocator2", allocator2_server.release()); + ASSERT_EQ(status, ZX_OK, ""); + + *allocator2_client_param = std::move(allocator2_client); + return ZX_OK; +} + zx_koid_t get_koid(zx_handle_t handle) { zx_info_handle_basic_t info; zx_status_t status = zx_object_get_info( @@ -60,8 +75,53 @@ return info.koid; } +zx_status_t verify_connectivity(zx::channel& allocator2_client) { + zx_status_t status; + + zx::channel collection_client; + zx::channel collection_server; + status = zx::channel::create(0, &collection_client, &collection_server); + ASSERT_EQ(status, ZX_OK, ""); + + status = fuchsia_sysmem_Allocator2AllocateNonSharedCollection(allocator2_client.get(), collection_server.release()); + ASSERT_EQ(status, ZX_OK, ""); + + status = fuchsia_sysmem_BufferCollectionSync(collection_client.get()); + ASSERT_EQ(status, ZX_OK, ""); + + return ZX_OK; +} + } // namespace +extern "C" bool test_sysmem_driver_connection(void) { + BEGIN_TEST; + + zx_status_t status; + zx::channel allocator2_client; + status = connect_to_sysmem_driver(&allocator2_client); + ASSERT_EQ(status, ZX_OK, ""); + + status = verify_connectivity(allocator2_client); + ASSERT_EQ(status, ZX_OK, ""); + + END_TEST; +} + +extern "C" bool test_sysmem_service_connection(void) { + BEGIN_TEST; + + zx_status_t status; + zx::channel allocator2_client; + status = connect_to_sysmem_service(&allocator2_client); + ASSERT_EQ(status, ZX_OK, ""); + + status = verify_connectivity(allocator2_client); + ASSERT_EQ(status, ZX_OK, ""); + + END_TEST; +} + extern "C" bool test_sysmem_token_one_participant_no_image_constraints(void) { BEGIN_TEST; @@ -512,6 +572,8 @@ } BEGIN_TEST_CASE(sysmem_tests) + RUN_TEST(test_sysmem_driver_connection) + RUN_TEST(test_sysmem_service_connection) RUN_TEST(test_sysmem_token_one_participant_no_image_constraints) RUN_TEST(test_sysmem_token_one_participant_with_image_constraints) RUN_TEST(test_sysmem_no_token)