OSDN Git Service

test_vendor_lib: Initial commit
authorDennis Cheng <dennischeng@google.com>
Tue, 16 Jun 2015 19:44:55 +0000 (12:44 -0700)
committerAndre Eisenbach <eisenbach@google.com>
Mon, 3 Aug 2015 17:53:30 +0000 (17:53 +0000)
Basic vendor library for a test Bluetooth controller. Currently consists
of mostly stub functions and objects and can only handle the reset
command (by immediately responding with a command complete event).
Implemented through a global EventDispatcher object which waits for data
from the HCI and directly returns the appropriate response.

Eventually, the dispatcher will manage a fake controller object that
will provide callbacks to be executed whenever events are processed by
the dispatcher. Unit tests are still in progress and will be in the next
upload.

Bug: 21586676
Change-Id: I1c6746f8b0f1732b89a1da13facecdd49b5ac1b6

18 files changed:
vendor_libs/BUILD.gn
vendor_libs/test_vendor_lib/Android.mk [new file with mode: 0644]
vendor_libs/test_vendor_lib/BUILD.gn [new file with mode: 0644]
vendor_libs/test_vendor_lib/include/bredr_controller.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/include/command_packet.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/include/event_packet.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/include/hci_handler.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/include/hci_transport.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/include/packet.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/include/packet_stream.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/src/bredr_controller.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/src/bt_vendor.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/src/command_packet.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/src/event_packet.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/src/hci_handler.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/src/hci_transport.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/src/packet.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/src/packet_stream.cc [new file with mode: 0644]

index 204162f..a088315 100644 (file)
@@ -16,6 +16,7 @@
 
 group("vendor-libs") {
   deps = [
-    "linux:bt-vendor-linux"
+    "linux:bt-vendor-linux",
+    "test_vendor_lib:test_vendor_lib",
   ]
 }
diff --git a/vendor_libs/test_vendor_lib/Android.mk b/vendor_libs/test_vendor_lib/Android.mk
new file mode 100644 (file)
index 0000000..b6be619
--- /dev/null
@@ -0,0 +1,33 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+BT_DIR := $(TOP_DIR)system/bt
+
+LOCAL_SRC_FILES := \
+    src/bredr_controller.cc \
+    src/bt_vendor.cc \
+    src/command_packet.cc \
+    src/event_packet.cc \
+    src/hci_handler.cc \
+    src/hci_transport.cc \
+    src/packet.cc \
+    src/packet_stream.cc \
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+    $(BT_DIR) \
+    $(BT_DIR)/hci/include \
+    $(BT_DIR)/osi/include \
+    $(BT_DIR)/stack/include \
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libchrome
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_MODULE := test-vendor
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/vendor_libs/test_vendor_lib/BUILD.gn b/vendor_libs/test_vendor_lib/BUILD.gn
new file mode 100644 (file)
index 0000000..dac1af6
--- /dev/null
@@ -0,0 +1,25 @@
+shared_library("test_vendor_lib") {
+  sources = [
+    "src/bredr_controller.cc",
+    "src/bt_vendor.cc",
+    "src/command_packet.cc",
+    "src/event_packet.cc",
+    "src/hci_handler.cc",
+    "src/hci_transport.cc",
+    "src/packet.cc",
+    "src/packet_stream.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+    # TODO(dennischeng): Ideally we should need to have the lines below for
+    # indirect includes.
+    "//osi/include",
+    "//stack/include",
+  ]
+
+  # TODO(dennischeng): Add libchrome as a dependency.
+}
+
+# TODO(dennischeng): Add a unit test target.
diff --git a/vendor_libs/test_vendor_lib/include/bredr_controller.h b/vendor_libs/test_vendor_lib/include/bredr_controller.h
new file mode 100644 (file)
index 0000000..4b35cbc
--- /dev/null
@@ -0,0 +1,86 @@
+//
+// Copyright 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.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+#include <unordered_map>
+
+#include <base/macros.h>
+
+namespace test_vendor_lib {
+
+// Emulates a BR/EDR controller by maintaining the link layer state machine
+// detailed in the Bluetooth Core Specification Version 4.2, Volume 2, Part B,
+// Section 8 (page 159). Provides actions corresponding to commands sent by the
+// HCI. These actions will be registered from a single global controller
+// instance as callbacks and called from the HciHandler.
+// TODO(dennischeng): Should the controller implement an interface provided by
+// the HciHandler and be used as a delegate (i.e. the HciHandler would hold a
+// controller object) instead of registering its methods as callbacks?
+class BREDRController {
+ public:
+  // Functions that operate on the global controller instance. Initialize()
+  // is called by the vendor library's Init() function to create the global
+  // controller and must be called before Get() and CleanUp().
+  // CleanUp() should be called when a call to TestVendorCleanUp() is made
+  // since the global controller should live throughout the entire time the test
+  // vendor library is in use.
+  static BREDRController* Get();
+
+  static void Initialize();
+
+  static void CleanUp();
+
+  // Controller commands. For error codes, see the Bluetooth Core Specification,
+  // Version 4.2, Volume 2, Part D (page 370).
+
+  // Resets the controller. For now, this just generates and sends a command
+  // complete event back to the HCI.
+  // Command parameters: none.
+  // Command response:
+  //   Status (1 octet)
+  //     0x00: Success.
+  //     0x01-0xFF: Failed. Check error codes.
+  void HciReset(const std::vector<std::uint8_t>& args);
+
+ private:
+  // There will only be a single global instance of this class.
+  BREDRController();
+
+  // The destructor can only be indirectly accessed through the static
+  // CleanUp() method that destructs the global controller.
+  ~BREDRController() = default;
+
+  // Registers command callbacks with the HciHandler instance so that they are
+  // fired when the corresponding opcode is received from the HCI. For now, each
+  // command must be individually registered. This allows for some flexibility
+  // in which commands are made available by which controller.
+  void RegisterHandlerCallbacks();
+
+  // Maintains the commands to be registered and used in the HciHandler object.
+  // Keys are command opcodes and values are the callbacks to handle each
+  // command.
+  std::unordered_map<std::uint16_t,
+                     std::function<void(const std::vector<std::uint8_t>&)>>
+      active_commands_;
+
+  // Disallow any copies of the singleton to be made.
+  DISALLOW_COPY_AND_ASSIGN(BREDRController);
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/command_packet.h b/vendor_libs/test_vendor_lib/include/command_packet.h
new file mode 100644 (file)
index 0000000..2d64ee1
--- /dev/null
@@ -0,0 +1,81 @@
+//
+// Copyright 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <cstdint>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace test_vendor_lib {
+
+// The following is specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.1 (page 470). Command Packets begin with a 3
+// octet header formatted as follows:
+// - Opcode: 2 octets
+//   - Opcode Group Field (OGF): Upper bits 10-15
+//   - Opcode Command Field (OCF): Lower bits 0-9
+// - Payload size (in octets): 1 octet
+// The header is followed by the payload, which contains command specific
+// parameters and has a maximum size of 255 octets. Valid command opcodes are
+// defined in stack/include/hcidefs.h. The OGF ranges from 0x00 to 0x3F, with
+// 0x3F reserved for vendor-specific debug functions. The OCF ranges from
+// 0x0000 to 0x03FF. Note that the payload size is the size in octets of the
+// command parameters and not the number of parameters. Finally, although the
+// parameters contained in the payload are command specific (including the size
+// and number of parameters), each parameter will be an integer number of octets
+// in size.
+class CommandPacket : public Packet {
+ public:
+  CommandPacket();
+
+  ~CommandPacket() override = default;
+
+  // Returns the command opcode as defined in stack/include/hcidefs.h.
+  // See the Bluetooth Core Specification Version 4.2, Volume 2, Part E,
+  // Section 7 for more information about each HCI commands and for a listing
+  // of their specific opcodes/OGF and OCF values.
+  std::uint16_t GetOpcode() const;
+
+  // Returns the 6 bit opcode group field that specifies the general category of
+  // the command. The OGF can be one of seven values:
+  // - 0x01: Link control commands
+  // - 0x02: Link policy commands
+  // - 0x03: Controller and baseband commands
+  // - 0x04: Informational parameters commands
+  // - 0x05: Status parameters commands
+  // - 0x06: Testing commands
+  // - 0x08: Low energy controller commands
+  // The upper 2 bits will be zero filled.
+  std::uint8_t GetOGF() const;
+
+  // Returns the 10 bit opcode command field that specifies an exact command
+  // within an opcode group field. The upper 6 bits will be zero filled.
+  std::uint16_t GetOCF() const;
+
+  // Size in octets of a command packet header, which consists of a 2 octet
+  // opcode and a 1 octet payload size.
+  static const size_t kCommandHeaderSize = 3;
+
+ private:
+  // Disallow any copies of the singleton to be made.
+  DISALLOW_COPY_AND_ASSIGN(CommandPacket);
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/event_packet.h b/vendor_libs/test_vendor_lib/include/event_packet.h
new file mode 100644 (file)
index 0000000..55765ea
--- /dev/null
@@ -0,0 +1,75 @@
+//
+// Copyright 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+namespace test_vendor_lib {
+
+// The following is specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.4 (page 477). Event Packets begin with a 2
+// octet header formatted as follows:
+// - Event code: 1 octet
+// - Payload size (in octets): 1 octet
+// The header is followed by the payload, which contains event specific
+// parameters and has a maximum size of 255 octets. Valid event codes are
+// listed in stack/include/hcidefs.h. They can range from 0x00 to 0xFF, with
+// 0xFF reserved for vendor specific debug events. Note the payload size
+// describes the total size of the event parameters and not the number of
+// parameters. The event parameters contained in the payload will be an integer
+// number of octets in size. Each flavor of event packet is created via a static
+// factory function that takes the event type-specific parameters and returns an
+// initialized event packet from that data.
+class EventPacket : public Packet {
+ public:
+  virtual ~EventPacket() override = default;
+
+  std::uint8_t GetEventCode() const;
+
+  // Static functions for creating event packets:
+
+  // Creates and returns a command complete event packet. See the Bluetooth
+  // Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14 (page 861)
+  // for more information about the command complete event.
+  // |num_hci_command_packets| indicates the number of HCI command packets the
+  // host can send to the controller. If |num_hci_command_packets| is 0, the
+  // controller would like to stop receiving commands from the host (to indicate
+  // readiness again, the controller sends a command complete event with
+  // |command_opcode| to 0x0000 (no op) and |num_hci_command_packets| > 1).
+  // |command_opcode| is the opcode of the command that caused this event.
+  // |return_parameters| will contain any event specific parameters that should
+  // be sent to the host.
+  static std::unique_ptr<EventPacket> CreateCommandCompleteEvent(
+      std::uint8_t num_hci_command_packets, std::uint16_t command_opcode,
+      const std::vector<std::uint8_t>& event_return_parameters);
+
+  // Size in octets of a data packet header, which consists of a 1 octet
+  // event code and a 1 octet payload size.
+  static const size_t kEventHeaderSize = 2;
+
+ private:
+  // Takes in the event parameters in |payload|. These parameters vary by event
+  // and are detailed in the Bluetooth Core Specification.
+  EventPacket(std::uint8_t event_code,
+              const std::vector<std::uint8_t>& payload);
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci_handler.h b/vendor_libs/test_vendor_lib/include/hci_handler.h
new file mode 100644 (file)
index 0000000..38ba6c0
--- /dev/null
@@ -0,0 +1,86 @@
+//
+// Copyright 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <cstdint>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace test_vendor_lib {
+
+// Dispatches packets to the appropriate controller handler. These handlers
+// must be registered by controller objects in order for commands to be
+// processed. Unregistered commands will perform no operations. Exposes two
+// callbacks, HandleCommand() and HandleData(), to be registered with a listener
+// object and called when commands and data are sent by the host.
+class HciHandler {
+ public:
+  // Functions that operate on the global handler instance. Initialize()
+  // is called by the vendor library's Init() function to create the global
+  // handler and must be called before Get() and CleanUp().
+  // CleanUp() should be called when a call to TestVendorCleanUp() is made
+  // since the global handler should live throughout the entire time the test
+  // vendor library is in use.
+  static HciHandler* Get();
+
+  static void Initialize();
+
+  static void CleanUp();
+
+  // Callback to be fired when a command packet is received from the HCI. Takes
+  // ownership of the packet and dispatches work to the controller through the
+  // callback registered with the command's opcode. After the controller
+  // finishes processing the command and the callback returns, the command
+  // packet is destroyed.
+  void HandleCommand(std::unique_ptr<CommandPacket> command);
+
+  // Creates the mapping from the opcode to the method |callback|.
+  // |callback|, which is provided by the controller, will be fired when its
+  // command opcode is received from the HCI.
+  void RegisterControllerCallback(
+      std::uint16_t opcode,
+      std::function<void(const std::vector<std::uint8_t> args)> callback);
+
+ private:
+  // There will only be a single global instance of this class.
+  HciHandler() = default;
+
+  // The destructor can only be indirectly accessed through the static
+  // CleanUp() method that destructs the global handler.
+  ~HciHandler() = default;
+
+  // Sets the command and data callbacks for when packets are received from the
+  // HCI.
+  void RegisterTransportCallbacks();
+
+  // Disallow any copies of the singleton to be made.
+  DISALLOW_COPY_AND_ASSIGN(HciHandler);
+
+  // Controller callbacks to be executed in handlers and registered in
+  // RegisterControllerCallback().
+  std::unordered_map<std::uint16_t,
+                     std::function<void(const std::vector<std::uint8_t> args)> >
+      callbacks_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci_transport.h b/vendor_libs/test_vendor_lib/include/hci_transport.h
new file mode 100644 (file)
index 0000000..ee490c5
--- /dev/null
@@ -0,0 +1,120 @@
+//
+// Copyright 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet_stream.h"
+
+#include <functional>
+#include <memory>
+
+#include <base/macros.h>
+
+extern "C" {
+#include <sys/epoll.h>
+}  // extern "C"
+
+namespace test_vendor_lib {
+
+// Manages communication channel between HCI and the controller. Listens for
+// available events from the host and receives packeted data when it is ready.
+// Also exposes a single send method for the controller to pass events back to
+// the HCI.
+// TODO(dennischeng): Create a nested delegate interface and have the HciHandler
+// subclass that interface instead of using callbacks.
+class HciTransport {
+ public:
+  // Returns the HCI's file descriptor for sending commands and data to the
+  // controller and for receiving events back.
+  int GetHciFd() const;
+
+  // Functions that operate on the global transport instance. Initialize()
+  // is called by the vendor library's Init() function to create the global
+  // transport and must be called before Get() and CleanUp().
+  // CleanUp() should be called when a call to TestVendorCleanUp() is made
+  // since the global transport should live throughout the entire time the test
+  // vendor library is in use.
+  static HciTransport* Get();
+
+  static void Initialize();
+
+  static void CleanUp();
+
+  // Creates the underlying socketpair and packet stream object. Returns true if
+  // the connection was successfully made.
+  bool Connect();
+
+  // Waits for events on the listener end of the socketpair. Fires the
+  // associated callback for each type of packet when data is received via
+  // |packet_stream_|. Returns false if an error occurs.
+  bool Listen();
+
+  // Sets the callback that is run when command packets are sent by the HCI.
+  void RegisterCommandCallback(
+      std::function<void(std::unique_ptr<CommandPacket>)> callback);
+
+  // TODO(dennischeng): Determine correct management of event object, what if
+  // write doesn't finish before destruction?
+  void SendEvent(const EventPacket& event);
+
+ private:
+  // Loops through the epoll event buffer and receives packets if they are
+  // ready. Fires the corresponding handler callback for each received packet.
+  bool ReceiveReadyPackets(const epoll_event& event_buffer,
+                          int num_ready);
+
+  // Reads in a command packet and calls the handler's command ready callback,
+  // passing owernship of the command packet to the handler.
+  void ReceiveReadyCommand();
+
+  // There will only be one global instance of the HCI transport used by
+  // bt_vendor.cc and accessed via the static GetInstance() function.
+  HciTransport();
+
+  // The destructor can only be indirectly accessed through the static
+  // CleanUp() method that destructs the global transport.
+  ~HciTransport();
+
+  // Sets up the epoll instance and registers the listener fd. Returns true on
+  // success.
+  // TODO(dennischeng): import base/ and use a MessageLoopForIO for event loop.
+  bool ConfigEpoll();
+
+  // Disallow any copies of the singleton to be made.
+  DISALLOW_COPY_AND_ASSIGN(HciTransport);
+
+  // Callback executed in Listen() for command packets.
+  std::function<void(std::unique_ptr<CommandPacket>)> command_callback_;
+
+  // File descriptor for epoll instance. Closed in the HciTransport destructor.
+  int epoll_fd_;
+
+  // Used to guard against multiple calls to Connect().
+  bool connected_;
+
+  // For performing packet IO.
+  PacketStream packet_stream_;
+
+  // The two ends of the socket pair used to communicate with the HCI.
+  // |socketpair_fds_[0]| is the listener end and is closed in the PacketStream
+  // object. |socketpair_fds_[1]| is the HCI end and is closed in bt_vendor.cc.
+  int socketpair_fds_[2];
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/packet.h b/vendor_libs/test_vendor_lib/include/packet.h
new file mode 100644 (file)
index 0000000..5c23cc6
--- /dev/null
@@ -0,0 +1,78 @@
+//
+// Copyright 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.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+extern "C" {
+#include "hci/include/hci_hal.h"
+}  // extern "C"
+
+namespace test_vendor_lib {
+
+// Abstract base class that manages a contiguous block of data and is
+// subclassed to provide type-specifc accessors on said data. Manages the data's
+// memory and guarantees the data's persistence for IO operations.
+class Packet {
+ public:
+  virtual ~Packet() = default;
+
+  // Returns the size in octets of the entire packet, which consists of the type
+  // octet, the header, and the payload.
+  size_t GetPacketSize() const;
+
+  const std::vector<std::uint8_t>& GetPayload() const;
+
+  std::uint8_t GetPayloadSize() const;
+
+  const std::vector<std::uint8_t>& GetHeader() const;
+
+  std::uint8_t GetHeaderSize() const;
+
+  serial_data_type_t GetType() const;
+
+  // Validates the packet by checking that the payload size in the header is
+  // accurate. If the size is not valid, returns false. Otherwise, the data in
+  // |header| and |payload| is copied into |header_| and |payload_|
+  // respectively. If an error occurs while the data is being copied, the
+  // contents of |header| and |payload| are guaranteed to be preserved. The
+  // packet object will assume ownership of the copied data for its entire
+  // lifetime.
+  bool Encode(const std::vector<std::uint8_t>& header,
+              const std::vector<std::uint8_t>& payload);
+
+ protected:
+  // Constructs an empty packet of type |type|. A call to Encode() shall be made
+  // to check and fill in the packet's data.
+  Packet(serial_data_type_t type);
+
+ private:
+  // Underlying containers for storing the actual packet, broken down into the
+  // packet header and the packet payload. Data is copied into the vectors
+  // during the constructor and becomes accessible (read only) to children
+  // through GetHeader() and GetPayload().
+  std::vector<std::uint8_t> header_;
+
+  std::vector<std::uint8_t> payload_;
+
+  // The packet type is one of DATA_TYPE_ACL, DATA_TYPE_COMMAND,
+  // DATA_TYPE_EVENT, or DATA_TYPE_SCO.
+  serial_data_type_t type_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/packet_stream.h b/vendor_libs/test_vendor_lib/include/packet_stream.h
new file mode 100644 (file)
index 0000000..77a30fc
--- /dev/null
@@ -0,0 +1,80 @@
+//
+// Copyright 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <cstdint>
+#include <vector>
+#include <memory>
+
+namespace test_vendor_lib {
+
+// Provides abstractions for IO with Packet objects. Used to receive commands
+// and data from the HCI and to send controller events back to the host.
+class PacketStream {
+ public:
+  // Constructs an invalid PacketStream object whose file descriptor must be set
+  // before use.
+  PacketStream();
+
+  // Closes |fd_|. Careful attention must be paid to when PacketStream objects
+  // are destructed because other objects may rely on the PacketStream's
+  // file descriptor.
+  virtual ~PacketStream();
+
+  // Reads a command packet and returns the packet back to the caller, along
+  // with the responsibility of managing the packet's memory.
+  std::unique_ptr<CommandPacket> ReceiveCommand();
+
+  // Reads and interprets a single octet as a packet type octet. Validates the
+  // type octet for correctness.
+  serial_data_type_t ReceivePacketType();
+
+  // Sends an event to the HCI. The memory management and ownership of the event
+  // is left with the caller.
+  void SendEvent(const EventPacket& event);
+
+  // Sets the file descriptor used in reading and writing. The PacketStream
+  // takes ownership of the descriptor at |fd| and closes it during destruction.
+  // This (as opposed to initializing fd_ in a constructor) helps prevent
+  // premature closing of the descriptor.
+  void SetFd(int fd);
+
+ private:
+  // Checks if |type| is in the valid range from DATA_TYPE_COMMAND to
+  // DATA_TYPE_SCO.
+  bool ValidateTypeOctet(serial_data_type_t type) const;
+
+  // Attempts to receive |num_octets_to_receive| into |buffer|, returning
+  // false if an error occurs.
+  bool ReceiveData(std::vector<std::uint8_t>& buffer,
+                  size_t num_octets_to_receive);
+
+  // Attempts to send |num_octets_to_send| from |source|, returning false if an
+  // error occurs.
+  bool SendData(const std::vector<std::uint8_t>& source,
+               size_t num_octets_to_send);
+
+  // File descriptor to read from and write to. This is the descriptor given to
+  // the HCI from the HciTransport.
+  int fd_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/bredr_controller.cc b/vendor_libs/test_vendor_lib/src/bredr_controller.cc
new file mode 100644 (file)
index 0000000..e2193be
--- /dev/null
@@ -0,0 +1,116 @@
+//
+// Copyright 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 "bredr_controller"
+
+#include "vendor_libs/test_vendor_lib/include/bredr_controller.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/hci_handler.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+extern "C" {
+#include "stack/include/hcidefs.h"
+#include "osi/include/log.h"
+
+#include <assert.h>
+}  // extern "C"
+
+namespace {
+
+// Controller constants and packaged command return parameters.
+// All page numbers refer to the Bluetooth Core Specification, Version 4.2,
+// Volume 2, Part E, Secion 7.1.
+// TODO(dennischeng): Move this into member variables so the controller is
+// configurable.
+
+// Included in certain events to indicate the successful completion of the
+// associated command.
+const uint8_t kReturnStatusSuccess = 0;
+
+// The default number encoded in event packets to indicate to the HCI how many
+// command packets it can send to the controller.
+const uint8_t kNumHciCommandPackets = 1;
+
+// Creates a command complete event and sends it back to the HCI.
+void SendCommandComplete(uint16_t command_opcode,
+                         const std::vector<uint8_t>& return_parameters) {
+  std::unique_ptr<test_vendor_lib::EventPacket> command_complete =
+      test_vendor_lib::EventPacket::CreateCommandCompleteEvent(
+          kNumHciCommandPackets, command_opcode, return_parameters);
+  // TODO(dennischeng): Should this dependency on HciTransport be removed?
+  test_vendor_lib::HciTransport::Get()->SendEvent(*command_complete);
+}
+
+// Sends a command complete event with no return parameters. This event is
+// typically sent for commands that can be completed immediately.
+void SendCommandCompleteSuccess(uint16_t command_opcode) {
+  SendCommandComplete(command_opcode, {kReturnStatusSuccess});
+}
+
+}  // namespace
+
+namespace test_vendor_lib {
+
+// Global controller instance used in the vendor library.
+// TODO(dennischeng): Should this be moved to an unnamed namespace?
+BREDRController* g_controller = nullptr;
+
+// static
+BREDRController* BREDRController::Get() {
+  // Initialize should have been called already.
+  // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+  assert(g_controller);
+  return g_controller;
+}
+
+// static
+void BREDRController::Initialize() {
+  // Multiple calls to Initialize() should not be made and the HciHandler should
+  // already be initialized.
+  // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+  assert(!g_controller);
+  assert(HciHandler::Get());
+  g_controller = new BREDRController();
+  g_controller->RegisterHandlerCallbacks();
+}
+
+// static
+void BREDRController::CleanUp() {
+  delete g_controller;
+  g_controller = nullptr;
+}
+
+BREDRController::BREDRController() {
+#define SET_HANDLER(opcode, command) \
+  active_commands_[opcode] =         \
+      std::bind(&BREDRController::command, this, std::placeholders::_1);
+  SET_HANDLER(HCI_RESET, HciReset);
+#undef SET_HANDLER
+}
+
+void BREDRController::RegisterHandlerCallbacks() {
+  HciHandler* handler = HciHandler::Get();
+  for (auto it = active_commands_.begin(); it != active_commands_.end(); ++it) {
+    handler->RegisterControllerCallback(it->first, it->second);
+  }
+}
+
+void BREDRController::HciReset(const std::vector<uint8_t>& /* args */) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  SendCommandCompleteSuccess(HCI_RESET);
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/bt_vendor.cc b/vendor_libs/test_vendor_lib/src/bt_vendor.cc
new file mode 100644 (file)
index 0000000..85f50aa
--- /dev/null
@@ -0,0 +1,146 @@
+//
+// Copyright 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 "bt_vendor"
+
+#include "hci/include/bt_vendor_lib.h"
+#include "vendor_libs/test_vendor_lib/include/bredr_controller.h"
+#include "vendor_libs/test_vendor_lib/include/hci_handler.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+#include <pthread.h>
+
+extern "C" {
+#include "osi/include/log.h"
+
+#include <assert.h>
+#include <unistd.h>
+}  // extern "C"
+
+namespace {
+bt_vendor_callbacks_t* vendor_callbacks;
+
+// Wrapper for kicking off HciTransport listening on its own thread.
+void* ListenEntryPoint(void* context) {
+  while ((static_cast<test_vendor_lib::HciTransport*>(context))->Listen());
+  LOG_INFO(LOG_TAG, "HciTransport stopped listening.");
+  return NULL;
+}
+}  // namespace
+
+namespace test_vendor_lib {
+
+// Initializes event handler for test device. |p_cb| are the callbacks to be
+// used by event handler. |local_bdaddr| points to the address of the Bluetooth
+// device. Returns 0 on success, -1 on error.
+static int TestVendorInitialize(const bt_vendor_callbacks_t* p_cb,
+                          unsigned char* /* local_bdaddr */) {
+  LOG_INFO(LOG_TAG, "Initializing test controller.");
+
+  // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+  assert(p_cb);
+  vendor_callbacks = const_cast<bt_vendor_callbacks_t*>(p_cb);
+
+  // Initialize global objects. The order of initialization does not matter,
+  // however all global objects should be initialized before any other work is
+  // done by the vendor library.
+  test_vendor_lib::HciTransport::Initialize();
+  test_vendor_lib::HciHandler::Initialize();
+  test_vendor_lib::BREDRController::Initialize();
+
+  // Create the connection to be used for communication between the HCI and
+  // the HciTransport object.
+  HciTransport* transporter = HciTransport::Get();
+  if (!transporter->Connect()) {
+    LOG_ERROR(LOG_TAG, "Error connecting HciTransport object to HCI.");
+    return -1;
+  }
+
+  // Start HciTransport listening on its own thread.
+  pthread_t transporter_thread;
+  pthread_create(&transporter_thread, NULL, &ListenEntryPoint, transporter);
+  return 0;
+}
+
+// Vendor specific operations. |opcode| is the opcode for Bluedroid's vendor op
+// definitions. |param| points to operation specific arguments. Return value is
+// dependent on the operation invoked, or -1 on error.
+static int TestVendorOp(bt_vendor_opcode_t opcode, void* param) {
+  LOG_INFO(LOG_TAG, "Opcode received in vendor library: %d", opcode);
+
+  HciTransport* transporter = HciTransport::Get();
+  if (!transporter) {
+    LOG_ERROR(LOG_TAG, "HciTransport was not initialized");
+    return -1;
+  }
+
+  switch (opcode) {
+    case BT_VND_OP_POWER_CTRL: {
+      LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_POWER_CTRL");
+      int* state = static_cast<int*>(param);
+      if (*state == BT_VND_PWR_OFF) {
+        LOG_INFO(LOG_TAG, "Turning Bluetooth off.");
+      } else if (*state == BT_VND_PWR_ON) {
+        LOG_INFO(LOG_TAG, "Turning Bluetooth on.");
+      }
+      return 0;
+    }
+
+    // Give the HCI its fd to communicate with the HciTransport.
+    case BT_VND_OP_USERIAL_OPEN: {
+      LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_USERIAL_OPEN");
+      int* transporter_fd = static_cast<int*>(param);
+      transporter_fd[0] = transporter->GetHciFd();
+      LOG_INFO(LOG_TAG, "Setting HCI's fd to: %d", transporter_fd[0]);
+      return 1;
+    }
+
+    // Close the HCI's file descriptor.
+    case BT_VND_OP_USERIAL_CLOSE:
+      LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_USERIAL_CLOSE");
+      LOG_INFO(LOG_TAG, "Closing HCI's fd (fd: %d)", transporter->GetHciFd());
+      close(transporter->GetHciFd());
+      return 1;
+
+    case BT_VND_OP_FW_CFG:
+      LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_FW_CFG");
+      vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+      return -1;
+
+    default:
+      LOG_INFO(LOG_TAG, "Op not recognized.");
+      return -1;
+  }
+  return 0;
+}
+
+// Closes the vendor interface and destroys global objects.
+static void TestVendorCleanUp(void) {
+  LOG_INFO(LOG_TAG, "Cleaning up vendor library.");
+  test_vendor_lib::BREDRController::CleanUp();
+  test_vendor_lib::HciHandler::CleanUp();
+  test_vendor_lib::HciTransport::CleanUp();
+}
+
+}  // namespace test_vendor_lib
+
+// Entry point of DLib.
+const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+  sizeof(bt_vendor_interface_t),
+  test_vendor_lib::TestVendorInitialize,
+  test_vendor_lib::TestVendorOp,
+  test_vendor_lib::TestVendorCleanUp
+};
diff --git a/vendor_libs/test_vendor_lib/src/command_packet.cc b/vendor_libs/test_vendor_lib/src/command_packet.cc
new file mode 100644 (file)
index 0000000..404ab7c
--- /dev/null
@@ -0,0 +1,45 @@
+//
+// Copyright 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 "command_packet"
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+
+extern "C" {
+#include "hci/include/hci_hal.h"
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+#include <assert.h>
+}  // extern "C"
+
+namespace test_vendor_lib {
+
+CommandPacket::CommandPacket() : Packet(DATA_TYPE_COMMAND) {}
+
+uint16_t CommandPacket::GetOpcode() const {
+  return 0 | (GetHeader()[0] | (GetHeader()[1] << 8));
+}
+
+uint8_t CommandPacket::GetOGF() const {
+  return HCI_OGF(GetOpcode());
+}
+
+uint16_t CommandPacket::GetOCF() const {
+  return HCI_OCF(GetOpcode());
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/event_packet.cc b/vendor_libs/test_vendor_lib/src/event_packet.cc
new file mode 100644 (file)
index 0000000..df3ec88
--- /dev/null
@@ -0,0 +1,59 @@
+//
+// Copyright 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 "event_packet"
+
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+
+extern "C" {
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+#include <assert.h>
+}  // extern "C"
+
+namespace test_vendor_lib {
+
+EventPacket::EventPacket(uint8_t event_code,
+                         const std::vector<uint8_t>& payload)
+    : Packet(DATA_TYPE_EVENT) {
+  Encode({event_code, static_cast<uint8_t>(payload.size())}, payload);
+}
+
+uint8_t EventPacket::GetEventCode() const {
+  return GetHeader()[0];
+}
+
+// static
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteEvent(
+    uint8_t num_hci_command_packets, uint16_t command_opcode,
+    const std::vector<uint8_t>& event_return_parameters) {
+  size_t payload_size = sizeof(num_hci_command_packets) +
+                        sizeof(command_opcode) + event_return_parameters.size();
+
+  std::vector<uint8_t> payload;
+  payload.reserve(payload_size);
+  payload.push_back(num_hci_command_packets);
+  payload.push_back(command_opcode);
+  payload.push_back(command_opcode >> 8);
+  std::copy(event_return_parameters.begin(), event_return_parameters.end(),
+            std::back_inserter(payload));
+
+  return std::unique_ptr<EventPacket>(
+      new EventPacket(HCI_COMMAND_COMPLETE_EVT, payload));
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/hci_handler.cc b/vendor_libs/test_vendor_lib/src/hci_handler.cc
new file mode 100644 (file)
index 0000000..e909ab8
--- /dev/null
@@ -0,0 +1,87 @@
+//
+// Copyright 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 "hci_handler"
+
+#include "vendor_libs/test_vendor_lib/include/hci_handler.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+extern "C" {
+#include "osi/include/log.h"
+
+#include <assert.h>
+}  // extern "C"
+
+namespace test_vendor_lib {
+
+// Global HciHandler instance used in the vendor library.
+// TODO(dennischeng): Should this be moved to an unnamed namespace?
+HciHandler* g_handler = nullptr;
+
+void HciHandler::RegisterTransportCallbacks() {
+  HciTransport* transporter = HciTransport::Get();
+  // Register the command packet callback with the HciTransport.
+  transporter->RegisterCommandCallback(
+      std::bind(&HciHandler::HandleCommand, this, std::placeholders::_1));
+}
+
+// static
+HciHandler* HciHandler::Get() {
+  // Initialize should have been called already.
+  // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+  assert(g_handler);
+  return g_handler;
+}
+
+// static
+void HciHandler::Initialize() {
+  // Multiple calls to Initialize() should not be made and the HciTransport
+  // should already be initialized.
+  // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+  assert(!g_handler);
+  assert(HciTransport::Get());
+  g_handler = new HciHandler();
+  g_handler->RegisterTransportCallbacks();
+}
+
+// static
+void HciHandler::CleanUp() {
+  delete g_handler;
+  g_handler = nullptr;
+}
+
+void HciHandler::HandleCommand(std::unique_ptr<CommandPacket> command) {
+  uint16_t opcode = command->GetOpcode();
+  LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode,
+           command->GetOGF(), command->GetOCF());
+
+  // The command hasn't been registered with the handler yet. There is nothing
+  // to do.
+  if (callbacks_.count(opcode) == 0) {
+    return;
+  }
+  std::function<void(const std::vector<uint8_t> args)> callback =
+      callbacks_[opcode];
+  callback(command->GetPayload());
+}
+
+void HciHandler::RegisterControllerCallback(
+    uint16_t opcode,
+    std::function<void(const std::vector<uint8_t> args)> callback) {
+  callbacks_[opcode] = callback;
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/hci_transport.cc b/vendor_libs/test_vendor_lib/src/hci_transport.cc
new file mode 100644 (file)
index 0000000..9488ef6
--- /dev/null
@@ -0,0 +1,175 @@
+//
+// Copyright 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 "hci_transport"
+
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+extern "C" {
+#include "stack/include/hcidefs.h"
+#include "osi/include/log.h"
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+}  // extern "C"
+
+namespace {
+// The maximum number of events in the epoll event buffer.
+const int kMaxEpollEvents = 10;
+}  // namespace
+
+namespace test_vendor_lib {
+
+// Global HciTransport instance used in the vendor library.
+// TODO(dennischeng): Should this be moved to an unnamed namespace?
+HciTransport* g_transporter = nullptr;
+
+HciTransport::HciTransport() : epoll_fd_(-1), connected_(false) {}
+
+HciTransport::~HciTransport() {
+  close(epoll_fd_);
+}
+
+bool HciTransport::ConfigEpoll() {
+  epoll_fd_ = epoll_create1(EPOLL_CLOEXEC);
+  epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = socketpair_fds_[0];
+  return epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, socketpair_fds_[0], &event) >= 0;
+}
+
+int HciTransport::GetHciFd() const {
+  return socketpair_fds_[1];
+}
+
+// static
+HciTransport* HciTransport::Get() {
+  // Initialize should have been called already.
+  // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+  assert(g_transporter);
+  return g_transporter;
+}
+
+// static
+void HciTransport::Initialize() {
+  // Multiple calls to Initialize should not be made.
+  // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+  assert(!g_transporter);
+  g_transporter = new HciTransport();
+}
+
+// static
+void HciTransport::CleanUp() {
+  delete g_transporter;
+  g_transporter = nullptr;
+}
+
+bool HciTransport::Connect() {
+  if (connected_) {
+    LOG_ERROR(LOG_TAG, "Error: transporter is already connected.");
+    return false;
+  }
+
+  // TODO(dennischeng): Use SOCK_SEQPACKET here.
+  if (socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds_) < 0) {
+    LOG_ERROR(LOG_TAG, "Error: creating socketpair in HciTransport.");
+    return false;
+  }
+
+  // Set the descriptor for the packet stream object. |packet_stream_| will take
+  // ownership of the descriptor.
+  packet_stream_.SetFd(socketpair_fds_[0]);
+
+  // Initialize epoll instance and set the file descriptor to listen on.
+  if (ConfigEpoll() < 0) {
+    LOG_ERROR(LOG_TAG, "Error: registering hci listener with epoll instance.");
+    return false;
+  }
+
+  connected_ = true;
+  return true;
+}
+
+bool HciTransport::Listen() {
+  epoll_event event_buffer[kMaxEpollEvents];
+  int num_ready;
+
+  // Check for ready events.
+  if ((num_ready = epoll_wait(epoll_fd_, event_buffer, kMaxEpollEvents, -1)) <
+      0) {
+     LOG_ERROR(LOG_TAG, "Error: epoll wait.");
+     return false;
+  }
+
+  return ReceiveReadyPackets(*event_buffer, num_ready);
+}
+
+bool HciTransport::ReceiveReadyPackets(const epoll_event& event_buffer,
+                                       int num_ready) {
+  for (int i = 0; i < num_ready; ++i) {
+    // Event has data ready to be read.
+    if ((&event_buffer)[i].events & EPOLLIN) {
+      LOG_INFO(LOG_TAG, "Event ready in HciTransport.");
+      serial_data_type_t packet_type = packet_stream_.ReceivePacketType();
+
+      switch (packet_type) {
+        case (DATA_TYPE_COMMAND): {
+          ReceiveReadyCommand();
+          return true;
+        }
+
+        case (DATA_TYPE_ACL): {
+          LOG_INFO(LOG_TAG, "ACL data packets not currently supported.");
+          return true;
+        }
+
+        case (DATA_TYPE_SCO): {
+          LOG_INFO(LOG_TAG, "SCO data packets not currently supported.");
+          return true;
+        }
+
+        // TODO(dennischeng): Add debug level assert here.
+        default: {
+          LOG_INFO(LOG_TAG,
+                   "Error received an invalid packet type from the HCI.");
+          return false;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+void HciTransport::ReceiveReadyCommand() {
+  std::unique_ptr<CommandPacket> command =
+      packet_stream_.ReceiveCommand();
+  command_callback_(std::move(command));
+}
+
+void HciTransport::RegisterCommandCallback(
+    std::function<void(std::unique_ptr<CommandPacket>)> callback) {
+  command_callback_ = callback;
+}
+
+void HciTransport::SendEvent(const EventPacket& event) {
+  packet_stream_.SendEvent(event);
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/packet.cc b/vendor_libs/test_vendor_lib/src/packet.cc
new file mode 100644 (file)
index 0000000..72f26b6
--- /dev/null
@@ -0,0 +1,67 @@
+//
+// Copyright 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 "packet"
+
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <algorithm>
+
+extern "C" {
+#include "osi/include/log.h"
+}  // extern "C"
+
+namespace test_vendor_lib {
+
+Packet::Packet(serial_data_type_t type) : type_(type) {}
+
+bool Packet::Encode(const std::vector<uint8_t>& header,
+                    const std::vector<uint8_t>& payload) {
+  if (header.back() != payload.size()) {
+    return false;
+  }
+  header_ = header;
+  payload_ = payload;
+  return true;
+}
+
+const std::vector<uint8_t>& Packet::GetHeader() const {
+  // Every packet must have a header.
+  assert(GetHeaderSize() > 0);
+  return header_;
+}
+
+uint8_t Packet::GetHeaderSize() const {
+  return header_.size();
+}
+
+size_t Packet::GetPacketSize() const {
+  return header_.size() + payload_.size() + sizeof(type_);
+}
+
+const std::vector<uint8_t>& Packet::GetPayload() const {
+  return payload_;
+}
+
+uint8_t Packet::GetPayloadSize() const {
+  return payload_.size();
+}
+
+serial_data_type_t Packet::GetType() const {
+  return type_;
+}
+
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/src/packet_stream.cc b/vendor_libs/test_vendor_lib/src/packet_stream.cc
new file mode 100644 (file)
index 0000000..1955140
--- /dev/null
@@ -0,0 +1,146 @@
+//
+// Copyright 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 "packet_stream"
+
+#include "vendor_libs/test_vendor_lib/include/packet_stream.h"
+
+extern "C" {
+#include "osi/include/log.h"
+
+#include <errno.h>
+#include <unistd.h>
+}  // extern "C"
+
+namespace test_vendor_lib {
+
+PacketStream::PacketStream() : fd_(-1) {}
+
+PacketStream::~PacketStream() {
+  close(fd_);
+}
+
+std::unique_ptr<CommandPacket> PacketStream::ReceiveCommand() {
+  std::vector<uint8_t> header;
+  if (!ReceiveData(header, CommandPacket::kCommandHeaderSize)) {
+    LOG_ERROR(LOG_TAG, "Error: receiving command header.");
+    return std::unique_ptr<CommandPacket>(nullptr);
+  }
+  std::vector<uint8_t> payload;
+  if (!ReceiveData(payload, header.back())) {
+    LOG_ERROR(LOG_TAG, "Error: receiving command payload.");
+    return std::unique_ptr<CommandPacket>(nullptr);
+  }
+  std::unique_ptr<CommandPacket> command(new CommandPacket());
+  if (!command->Encode(header, payload)) {
+    LOG_ERROR(LOG_TAG, "Error: encoding command packet.");
+    return std::unique_ptr<CommandPacket>(nullptr);
+  }
+  return command;
+}
+
+serial_data_type_t PacketStream::ReceivePacketType() {
+  LOG_INFO(LOG_TAG, "Receiving packet type.");
+
+  std::vector<uint8_t> raw_type_octet;
+  if (!ReceiveData(raw_type_octet, 1)) {
+    // TODO(dennischeng): Proper error handling.
+    LOG_ERROR(LOG_TAG, "Error: Could not receive packet type.");
+  }
+
+  // Check that the type octet received is in the valid range, i.e. the packet
+  // must be a command or data.
+  serial_data_type_t type = static_cast<serial_data_type_t>(raw_type_octet[0]);
+  if (!ValidateTypeOctet(type)) {
+    // TODO(dennischeng): Proper error handling.
+    LOG_ERROR(LOG_TAG, "Error: Received invalid packet type.");
+  }
+
+  return type;
+}
+
+void PacketStream::SendEvent(const EventPacket& event) {
+  LOG_INFO(LOG_TAG, "Sending event with event code: 0x%04X",
+           event.GetEventCode());
+  LOG_INFO(LOG_TAG, "Sending event with size: %zu octets",
+           event.GetPacketSize());
+
+  // TODO(dennischeng): Decide if three separate writes is necessary here.
+  if (!SendData({event.GetType()}, 1)) {
+    // TODO(dennischeng): Proper error handling.
+    LOG_ERROR(LOG_TAG, "Error: Could not send event type.");
+    return;
+  }
+  if (!SendData(event.GetHeader(), event.GetHeaderSize())) {
+    // TODO(dennischeng): Proper error handling.
+    LOG_ERROR(LOG_TAG, "Error: Could not send event header.");
+    return;
+  }
+  if (!SendData(event.GetPayload(), event.GetPayloadSize())) {
+    // TODO(dennischeng): Proper error handling.
+    LOG_ERROR(LOG_TAG, "Error: Could not send event payload.");
+    return;
+  }
+  LOG_INFO(LOG_TAG, "Event sent.");
+}
+
+void PacketStream::SetFd(int fd) {
+  if (fd >= 0) {
+    fd_ = fd;
+  }
+}
+
+bool PacketStream::ValidateTypeOctet(serial_data_type_t type) const {
+  LOG_INFO(LOG_TAG, "Signal octet is 0x%02X.", type);
+  // The only types of packets that should be received from the HCI are command
+  // packets and data packets.
+  return (type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO);
+}
+
+bool PacketStream::ReceiveData(std::vector<uint8_t>& buffer,
+                              size_t num_octets_to_receive) {
+  buffer.resize(num_octets_to_receive);
+  size_t octets_remaining = num_octets_to_receive;
+  do {
+    int num_octets_received = read(
+        fd_,
+        &buffer[num_octets_to_receive - octets_remaining],
+        octets_remaining);
+    if (num_octets_received < 0) {
+      return false;
+    }
+    octets_remaining -= num_octets_received;
+  } while (octets_remaining > 0);
+  return true;
+}
+
+bool PacketStream::SendData(const std::vector<uint8_t>& source,
+                           size_t num_octets_to_send) {
+  // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+  assert(source.size() >= num_octets_to_send);
+  size_t octets_remaining = num_octets_to_send;
+  do {
+    int num_octets_sent = write(
+        fd_, &source[num_octets_to_send - octets_remaining], octets_remaining);
+    if (num_octets_sent < 0) {
+      return false;
+    }
+    octets_remaining -= num_octets_sent;
+  } while (octets_remaining > 0);
+  return true;
+}
+
+}  // namespace test_vendor_lib