aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Langlois <pierre.langlois@arm.com>2015-01-08 14:37:28 +0000
committerPierre Langlois <pierre.langlois@arm.com>2016-03-04 17:37:15 +0000
commit557d3c422c06f739025482176cd64784c9a51709 (patch)
tree57e20fdb0eb5b605b29ac54151493b6c58278eb9
parentbf39b724a17a58c925b311d4aa6eb49bfe06688d (diff)
downloadkdbinder-557d3c422c06f739025482176cd64784c9a51709.tar.gz
libkdbinder: kdbus: add a Connection interface
This patch introduces a new interface for opening connection on a bus. Opening a connection on a bus is done by send a kdbus_cmd_hello command to `/sys/fs/kdbus/0-mybus/bus`. Changes: * New Connection::hello factory methods returning a std::unique_ptr<Connection>. * New function for sending a kdbus_cmd_hello command. We need to initialize different fields of the command before sending it, and also retreive information from it once the kernel has handled it. This is done by adding hooks before and after the ioctl call in the base send_command function. For example, we need to read the ID that KDBUS assigned to our connection once the kdbus_cmd_hello was sent: ~~~ template<typename... ITEMS> const ReplyHello send_command_hello(FILE *file, uint64_t pool_size, ITEMS... item) { uint64_t id = 0; auto reply = send_command<struct kdbus_cmd_hello>( file, 0, KDBUS_CMD_HELLO, // Initialize extra fields before the command is sent. [&pool_size](struct kdbus_cmd_hello *cmd){ cmd->pool_size = pool_size; cmd->attach_flags_send = 0; cmd->attach_flags_recv = 0; }, // Retreive the ID that KDBUS gave us. [&id](const kdbus_cmd_hello& cmd){ id = cmd.id; }, item...); return ReplyHello(reply, id); } ~~~ * New ItemConnDescription string item. Change-Id: Ic70a7070fcb602e34af6c59343e8b15748957120
-rw-r--r--include/kdbinder/kdbus/KDBinder.h43
-rw-r--r--libs/kdbinder/Android.mk3
-rw-r--r--libs/kdbinder/kdbus/bus.cpp2
-rw-r--r--libs/kdbinder/kdbus/cmds.h43
-rw-r--r--libs/kdbinder/kdbus/connection.cpp86
-rw-r--r--libs/kdbinder/kdbus/items.h2
-rw-r--r--libs/kdbinder/tests/Android.mk3
-rw-r--r--libs/kdbinder/tests/kdbus/connection.cpp33
8 files changed, 210 insertions, 5 deletions
diff --git a/include/kdbinder/kdbus/KDBinder.h b/include/kdbinder/kdbus/KDBinder.h
index 5c7f5b5..7f85de3 100644
--- a/include/kdbinder/kdbus/KDBinder.h
+++ b/include/kdbinder/kdbus/KDBinder.h
@@ -17,20 +17,22 @@
#define INCLUDE_KDBINDER_KDBINDER_H_
#include <assert.h>
+#include <sys/mman.h>
-// TODO(pielan01): Why do we need CHAR_BIT here?
+// TODO: Why do we need CHAR_BIT here?
#define CHAR_BIT 8
#include <vector>
#undef CHAR_BIT
#include <string>
#include <memory>
+#include <cstdio>
// Use ASSERT for assertions in debug builds.
// Use CHECK for assertions in debug and release builds.
// Use STATIC_ASSERT for compile time assertions.
#define ASSERT(cond) assert(cond)
-// TODO(pielan01): Use LOGCAT
+// TODO: Use LOGCAT
#define CHECK(cond) if(!(cond)) std::terminate()
#define STATIC_ASSERT(cond) static_assert(cond, "")
@@ -74,6 +76,43 @@ class Bus {
std::unique_ptr<FILE, decltype(&fclose)> control_file_;
};
+class Connection {
+ public:
+ static std::unique_ptr<Connection> hello(const Bus& bus,
+ const std::string& name);
+ static std::unique_ptr<Connection> hello(const std::string& path,
+ const std::string& name);
+
+ static constexpr size_t kPoolSize() {
+ // TODO: This magic number was taken from KDBUS's test suite, we
+ // should tune it.
+ return 16 * 1024LU * 1024LU;
+ }
+
+ ~Connection() = default;
+
+ // A Connection is not copyable as it has exclusive ownership of a
+ // memory mapped area.
+ Connection(const Connection&) = delete;
+ Connection& operator=(const Connection&) = delete;
+
+ Connection(Connection&&) = default;
+ Connection& operator=(Connection&&) = default;
+
+ const uint64_t id;
+
+ private:
+ Connection(FILE* bus_file, uint64_t id, void *buf)
+ : id(id),
+ // There is no need to call munmap as closing the bus_file_ file
+ // descriptor will take care of it.
+ buf_(buf, [](void *){}),
+ bus_file_(bus_file, &fclose) {}
+
+ std::unique_ptr<void, void (*)(void *)> buf_;
+ std::unique_ptr<FILE, decltype(&fclose)> bus_file_;
+};
+
} // namespace kdbus
} // namespace android
diff --git a/libs/kdbinder/Android.mk b/libs/kdbinder/Android.mk
index 4755f91..0a027e5 100644
--- a/libs/kdbinder/Android.mk
+++ b/libs/kdbinder/Android.mk
@@ -13,7 +13,8 @@
# limitations under the License.
kdbinder_sources := \
- kdbus/bus.cpp
+ kdbus/bus.cpp \
+ kdbus/connection.cpp
kdbinder_libs := libcutils
diff --git a/libs/kdbinder/kdbus/bus.cpp b/libs/kdbinder/kdbus/bus.cpp
index b512f96..d153ca3 100644
--- a/libs/kdbinder/kdbus/bus.cpp
+++ b/libs/kdbinder/kdbus/bus.cpp
@@ -44,7 +44,7 @@ std::unique_ptr<Bus> Bus::make(const std::string& name) {
// struct kdbus_cmd_make takes to following items:
// - KDBUS_ITEM_BLOOM_PARAMETER: bus-wide bloom parameter,
- // TODO(pielan01): why does each bus need this? What does it do?
+ // TODO: why does each bus need this? What does it do?
// - KDBUS_ITEM_MAKE_NAME: name of the bus
auto reply = send_command_make(control_file,
ItemBloomParameter(64, 1),
diff --git a/libs/kdbinder/kdbus/cmds.h b/libs/kdbinder/kdbus/cmds.h
index 37c8c7e..135f6fa 100644
--- a/libs/kdbinder/kdbus/cmds.h
+++ b/libs/kdbinder/kdbus/cmds.h
@@ -25,6 +25,7 @@
#include <vector>
#include <memory>
#include <initializer_list>
+#include <functional>
namespace android {
namespace kdbus {
@@ -42,6 +43,12 @@ template<typename TYPE, typename... ITEMS>
const Reply send_command(FILE *file,
uint64_t flags,
int ioctl_cmd,
+ // Initialize extra fields before sending the
+ // command.
+ const std::function<void(TYPE *)>& pre_ioctl,
+ // Retreive data from the kernel, after the
+ // command is sent.
+ const std::function<void(const TYPE&)>& post_ioctl,
ITEMS... item) {
// We cannot construct an initializer_list of items by value since Item is a
// base class and contains virtual methods.
@@ -59,6 +66,7 @@ const Reply send_command(FILE *file,
// Every command has a size and flags.
cmd->size = size;
cmd->flags = flags;
+ pre_ioctl(cmd);
// Write each items on the stack, we have allocated just enough room for
// them.
@@ -71,6 +79,7 @@ const Reply send_command(FILE *file,
if (ret < 0) {
return Reply(ret, std::string(strerror(-errno)));
} else {
+ post_ioctl(*cmd);
return Reply(ret, "");
}
}
@@ -80,9 +89,43 @@ inline const Reply send_command_make(FILE *file, ITEMS...item) {
return send_command<struct kdbus_cmd_make>(file,
KDBUS_MAKE_ACCESS_WORLD,
KDBUS_CMD_BUS_MAKE,
+ [](struct kdbus_cmd_make *){},
+ [](const kdbus_cmd_make&){},
item...);
}
+struct ReplyHello : Reply {
+ ReplyHello(const Reply& reply, uint64_t id)
+ : Reply(reply),
+ id(id) {}
+ const uint64_t id;
+};
+
+template<typename... ITEMS>
+inline const ReplyHello send_command_hello(FILE *file,
+ uint64_t pool_size,
+ ITEMS... item) {
+ uint64_t id = 0;
+ auto reply = send_command<struct kdbus_cmd_hello>(
+ file,
+ 0,
+ KDBUS_CMD_HELLO,
+ [&pool_size](struct kdbus_cmd_hello *cmd){
+ cmd->pool_size = pool_size;
+ // For now, we do not want KDBUS to attach any extra metadata on
+ // messages.
+ cmd->attach_flags_send = 0;
+ cmd->attach_flags_recv = 0;
+ },
+ [&id](const kdbus_cmd_hello& cmd){
+ // Retreive the ID that KDBUS gave us.
+ id = cmd.id;
+ },
+ item...);
+
+ return ReplyHello(reply, id);
+}
+
} // namespace kdbus
} // namespace android
diff --git a/libs/kdbinder/kdbus/connection.cpp b/libs/kdbinder/kdbus/connection.cpp
new file mode 100644
index 0000000..8a896ba
--- /dev/null
+++ b/libs/kdbinder/kdbus/connection.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "KDBUS::Connection"
+#include <cutils/log.h>
+
+#include <kdbinder/kdbus/KDBinder.h>
+#include "cmds.h"
+#include "items.h"
+
+#include <kdbus.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include <vector>
+#include <string>
+
+namespace android {
+namespace kdbus {
+
+std::unique_ptr<Connection> Connection::hello(
+ const Bus& bus,
+ const std::string& connection_name) {
+ return hello(bus.name, connection_name);
+}
+
+std::unique_ptr<Connection> Connection::hello(
+ const std::string& bus_name,
+ const std::string& connection_name) {
+ std::string path(Bus::domain + bus_name + "/bus");
+
+ FILE *bus_file = fopen(path.c_str(), "re");
+ if (bus_file == nullptr) {
+ ALOGE("Could not open bus file %s: %s\n", path.c_str(), strerror(errno));
+ return nullptr;
+ }
+
+ // struct kdbus_cmd_hello takes the following items:
+ // - KDBUS_ITEM_CONN_DESCRIPTION: name of the connection
+ auto reply = send_command_hello(bus_file,
+ Connection::kPoolSize(),
+ ItemConnDescription(connection_name));
+ if (reply.error_code < 0) {
+ ALOGE("Could not connect to Bus \"%s\" with Connection \"%s\": %s\n",
+ bus_name.c_str(),
+ connection_name.c_str(),
+ reply.error_string.c_str());
+ fclose(bus_file);
+ return nullptr;
+ }
+
+ // map a memory region for future communications. Note that we
+ // do not need to unmap it since it will be done automatically by the
+ // kernel when we close the file descriptor.
+ void *buf = mmap(NULL, Connection::kPoolSize(), PROT_READ, MAP_SHARED, fileno(bus_file), 0);
+ if (buf == MAP_FAILED) {
+ ALOGE("Could not mmap a memory pool for Connection %s: %s\n",
+ connection_name.c_str(),
+ strerror(errno));
+ fclose(bus_file);
+ return nullptr;
+ }
+
+ ALOGI("New Connection on Bus \"%s\": ID %d, description \"%s\"",
+ bus_name.c_str(),
+ (int) reply.id,
+ connection_name.c_str());
+
+ return std::unique_ptr<Connection>(new Connection(bus_file, reply.id, buf));
+}
+
+} // namespace kdbus
+} // namespace android
diff --git a/libs/kdbinder/kdbus/items.h b/libs/kdbinder/kdbus/items.h
index 9969869..c247e46 100644
--- a/libs/kdbinder/kdbus/items.h
+++ b/libs/kdbinder/kdbus/items.h
@@ -106,6 +106,8 @@ class ItemBloomParameter : public Item {
struct kdbus_bloom_parameter bloom_;
};
+using ItemConnDescription = ItemStr<KDBUS_ITEM_CONN_DESCRIPTION>;
+
} // namespace kdbus
} // namespace android
diff --git a/libs/kdbinder/tests/Android.mk b/libs/kdbinder/tests/Android.mk
index 3c466dd..587a08f 100644
--- a/libs/kdbinder/tests/Android.mk
+++ b/libs/kdbinder/tests/Android.mk
@@ -14,7 +14,8 @@
#
kdbinderKDBUSTest_sources := \
- kdbus/bus.cpp
+ kdbus/bus.cpp \
+ kdbus/connection.cpp
LOCAL_PATH := $(call my-dir)
diff --git a/libs/kdbinder/tests/kdbus/connection.cpp b/libs/kdbinder/tests/kdbus/connection.cpp
new file mode 100644
index 0000000..a848e40
--- /dev/null
+++ b/libs/kdbinder/tests/kdbus/connection.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <gtest/gtest.h>
+
+#include <kdbinder/kdbus/KDBinder.h>
+
+using Bus = android::kdbus::Bus;
+using Connection = android::kdbus::Connection;
+
+TEST(Connection, hello) {
+ auto b = Bus::make("test-bus");
+ auto c1 = Connection::hello(*b, "test-conn");
+ auto c2 = Connection::hello(*b, "test-conn");
+
+ ASSERT_TRUE(c2 != nullptr);
+ ASSERT_TRUE(c1->id == 1);
+ ASSERT_TRUE(c2 != nullptr);
+ ASSERT_TRUE(c2->id == 2);
+}