Expose the underlying shared memory buffers from ShmEventLoop

For advanced use cases, this is handy to set up these memory regions
specially.

Change-Id: I7e858d3af5f3fa51f980e0e4cab5dfcfa7b83fd9
diff --git a/aos/events/shm_event_loop_test.cc b/aos/events/shm_event_loop_test.cc
index d33f496..949d7db 100644
--- a/aos/events/shm_event_loop_test.cc
+++ b/aos/events/shm_event_loop_test.cc
@@ -181,6 +181,34 @@
   EXPECT_EQ(times.size(), 2u);
 }
 
+// Test GetWatcherSharedMemory in a few basic scenarios.
+TEST(ShmEventLoopDeathTest, GetWatcherSharedMemory) {
+  ShmEventLoopTestFactory factory;
+  auto generic_loop1 = factory.MakePrimary("primary");
+  ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
+  const auto channel = configuration::GetChannel(
+      loop1->configuration(), "/test", TestMessage::GetFullyQualifiedName(),
+      loop1->name(), loop1->node());
+
+  // First verify it handles an invalid channel reasonably.
+  EXPECT_DEATH(loop1->GetWatcherSharedMemory(channel),
+               "No watcher found for channel");
+
+  // Then, actually create a watcher, and verify it returns something sane.
+  loop1->MakeWatcher("/test", [](const TestMessage &) {});
+  EXPECT_FALSE(loop1->GetWatcherSharedMemory(channel).empty());
+}
+
+TEST(ShmEventLoopTest, GetSenderSharedMemory) {
+  ShmEventLoopTestFactory factory;
+  auto generic_loop1 = factory.MakePrimary("primary");
+  ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
+
+  // check that GetSenderSharedMemory returns non-null/non-empty memory span
+  auto sender = loop1->MakeSender<TestMessage>("/test");
+  EXPECT_FALSE(loop1->GetSenderSharedMemory(&sender).empty());
+}
+
 // TODO(austin): Test that missing a deadline with a timer recovers as expected.
 
 }  // namespace testing