Bug 1171017: Move classes from ipc/bluetooth to ipc/hal, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Mon, 15 Jun 2015 14:44:03 +0200
changeset 279587 69dcab10d33d39f2a51ac845d77d6631d8898906
parent 279586 9d9012f0bedad0317ac96d019f41ae6cecc5a097
child 279588 27aced864f2c777bdc7b1a58ab027c3680ac1328
push idunknown
push userunknown
push dateunknown
reviewersshuang
bugs1171017
milestone41.0a1
Bug 1171017: Move classes from ipc/bluetooth to ipc/hal, r=shuang The class |DaemonSocket| and its helpers implement a service- neutral connection to a HAL daemon. This patch moves the code to an appropriate directory and breaks up the code into smaller pieces.
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
ipc/bluetooth/BluetoothDaemonConnection.cpp
ipc/bluetooth/BluetoothDaemonConnection.h
ipc/bluetooth/BluetoothDaemonConnectionConsumer.cpp
ipc/bluetooth/BluetoothDaemonConnectionConsumer.h
ipc/bluetooth/moz.build
ipc/hal/DaemonSocket.cpp
ipc/hal/DaemonSocket.h
ipc/hal/DaemonSocketConsumer.cpp
ipc/hal/DaemonSocketConsumer.h
ipc/hal/DaemonSocketPDU.cpp
ipc/hal/DaemonSocketPDU.h
ipc/hal/moz.build
ipc/moz.build
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluedroid_bluetoothdaemonhelpers_h__
 #define mozilla_dom_bluetooth_bluedroid_bluetoothdaemonhelpers_h__
 
 #include "BluetoothCommon.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
-#include "mozilla/ipc/BluetoothDaemonConnection.h"
+#include "mozilla/ipc/DaemonSocketPDU.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla::ipc;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // Helper structures
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
@@ -12,16 +12,17 @@
 #include "BluetoothDaemonAvrcpInterface.h"
 #include "BluetoothDaemonConnector.h"
 #include "BluetoothDaemonGattInterface.h"
 #include "BluetoothDaemonHandsfreeInterface.h"
 #include "BluetoothDaemonHelpers.h"
 #include "BluetoothDaemonSetupInterface.h"
 #include "BluetoothDaemonSocketInterface.h"
 #include "BluetoothInterfaceHelpers.h"
+#include "mozilla/ipc/DaemonSocket.h"
 #include "mozilla/ipc/ListenSocket.h"
 #include "mozilla/unused.h"
 #include "prrng.h"
 
 using namespace mozilla::ipc;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
 #define mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
 
 #include "BluetoothInterface.h"
-#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h"
+#include "mozilla/ipc/DaemonSocketConsumer.h"
 #include "mozilla/ipc/ListenSocketConsumer.h"
 
 namespace mozilla {
 namespace ipc {
 
 class DaemonSocket;
 class ListenSocket;
 
rename from ipc/bluetooth/BluetoothDaemonConnection.cpp
rename to ipc/hal/DaemonSocket.cpp
--- a/ipc/bluetooth/BluetoothDaemonConnection.cpp
+++ b/ipc/hal/DaemonSocket.cpp
@@ -1,24 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "BluetoothDaemonConnection.h"
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h"
-#include "mozilla/ipc/DataSocket.h"
-#include "nsTArray.h"
-#include "nsXULAppAPI.h"
+#include "DaemonSocket.h"
+#include "mozilla/ipc/DaemonSocketConsumer.h"
+#include "mozilla/ipc/DaemonSocketPDU.h"
 
 #ifdef CHROMIUM_LOG
 #undef CHROMIUM_LOG
 #endif
 
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
 #define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "I/O", args);
@@ -26,192 +19,16 @@
 #include <stdio.h>
 #define IODEBUG true
 #define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
 #endif
 
 namespace mozilla {
 namespace ipc {
 
-// The connection to the Bluetooth daemon is established
-// using an abstract socket name. The \0 prefix will be added
-// by the |Connect| method.
-static const char sBluetoothdSocketName[] = "bluez_hal_socket";
-
-//
-// DaemonSocketPDU
-//
-
-DaemonSocketPDU::DaemonSocketPDU(uint8_t aService, uint8_t aOpcode,
-                                       uint16_t aPayloadSize)
-  : mConsumer(nullptr)
-  , mUserData(nullptr)
-{
-  // Allocate memory
-  size_t availableSpace = HEADER_SIZE + aPayloadSize;
-  ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace);
-
-  // Reserve PDU header
-  uint8_t* data = Append(HEADER_SIZE);
-  MOZ_ASSERT(data);
-
-  // Setup PDU header
-  data[OFF_SERVICE] = aService;
-  data[OFF_OPCODE] = aOpcode;
-  memcpy(data + OFF_LENGTH, &aPayloadSize, sizeof(aPayloadSize));
-}
-
-DaemonSocketPDU::DaemonSocketPDU(size_t aPayloadSize)
-  : mConsumer(nullptr)
-  , mUserData(nullptr)
-{
-  size_t availableSpace = HEADER_SIZE + aPayloadSize;
-  ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace);
-}
-
-DaemonSocketPDU::~DaemonSocketPDU()
-{
-  nsAutoArrayPtr<uint8_t> data(GetBuffer());
-  ResetBuffer(nullptr, 0, 0, 0);
-}
-
-void
-DaemonSocketPDU::GetHeader(uint8_t& aService, uint8_t& aOpcode,
-                              uint16_t& aPayloadSize)
-{
-  memcpy(&aService, GetData(OFF_SERVICE), sizeof(aService));
-  memcpy(&aOpcode, GetData(OFF_OPCODE), sizeof(aOpcode));
-  memcpy(&aPayloadSize, GetData(OFF_LENGTH), sizeof(aPayloadSize));
-}
-
-ssize_t
-DaemonSocketPDU::Send(int aFd)
-{
-  struct iovec iv;
-  memset(&iv, 0, sizeof(iv));
-  iv.iov_base = GetData(GetLeadingSpace());
-  iv.iov_len = GetSize();
-
-  struct msghdr msg;
-  memset(&msg, 0, sizeof(msg));
-  msg.msg_iov = &iv;
-  msg.msg_iovlen = 1;
-  msg.msg_control = nullptr;
-  msg.msg_controllen = 0;
-
-  ssize_t res = TEMP_FAILURE_RETRY(sendmsg(aFd, &msg, 0));
-  if (res < 0) {
-    MOZ_ASSERT(errno != EBADF); /* internal error */
-    OnError("sendmsg", errno);
-    return -1;
-  }
-
-  Consume(res);
-
-  if (mConsumer) {
-    // We successfully sent a PDU, now store the
-    // result runnable in the consumer.
-    mConsumer->StoreUserData(*this);
-  }
-
-  return res;
-}
-
-#define CMSGHDR_CONTAINS_FD(_cmsghdr) \
-    ( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \
-      ((_cmsghdr)->cmsg_type == SCM_RIGHTS) )
-
-ssize_t
-DaemonSocketPDU::Receive(int aFd)
-{
-  struct iovec iv;
-  memset(&iv, 0, sizeof(iv));
-  iv.iov_base = GetData(0);
-  iv.iov_len = GetAvailableSpace();
-
-  uint8_t cmsgbuf[CMSG_SPACE(sizeof(int))];
-
-  struct msghdr msg;
-  memset(&msg, 0, sizeof(msg));
-  msg.msg_iov = &iv;
-  msg.msg_iovlen = 1;
-  msg.msg_control = cmsgbuf;
-  msg.msg_controllen = sizeof(cmsgbuf);
-
-  ssize_t res = TEMP_FAILURE_RETRY(recvmsg(aFd, &msg, MSG_NOSIGNAL));
-  if (res < 0) {
-    MOZ_ASSERT(errno != EBADF); /* internal error */
-    OnError("recvmsg", errno);
-    return -1;
-  }
-  if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) {
-    return -1;
-  }
-
-  SetRange(0, res);
-
-  struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg);
-
-  for (; chdr; chdr = CMSG_NXTHDR(&msg, chdr)) {
-    if (NS_WARN_IF(!CMSGHDR_CONTAINS_FD(chdr))) {
-      continue;
-    }
-    // Retrieve sent file descriptor. If multiple file descriptors
-    // have been sent, we close all but the final one.
-    mReceivedFd = *(static_cast<int*>(CMSG_DATA(chdr)));
-  }
-
-  return res;
-}
-
-int
-DaemonSocketPDU::AcquireFd()
-{
-  return mReceivedFd.forget();
-}
-
-nsresult
-DaemonSocketPDU::UpdateHeader()
-{
-  size_t len = GetPayloadSize();
-  if (len >= MAX_PAYLOAD_LENGTH) {
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  uint16_t len16 = static_cast<uint16_t>(len);
-
-  memcpy(GetData(OFF_LENGTH), &len16, sizeof(len16));
-
-  return NS_OK;
-}
-
-size_t
-DaemonSocketPDU::GetPayloadSize() const
-{
-  MOZ_ASSERT(GetSize() >= HEADER_SIZE);
-
-  return GetSize() - HEADER_SIZE;
-}
-
-void
-DaemonSocketPDU::OnError(const char* aFunction, int aErrno)
-{
-  CHROMIUM_LOG("%s failed with error %d (%s)",
-               aFunction, aErrno, strerror(aErrno));
-}
-
-//
-// DaemonSocketIOConsumer
-//
-
-DaemonSocketIOConsumer::DaemonSocketIOConsumer()
-{ }
-
-DaemonSocketIOConsumer::~DaemonSocketIOConsumer()
-{ }
-
 //
 // DaemonSocketIO
 //
 
 class DaemonSocketIO final : public ConnectionOrientedSocketIO
 {
 public:
   DaemonSocketIO(MessageLoop* aConsumerLoop,
@@ -391,17 +208,17 @@ DaemonSocket::SendSocketData(UnixSocketI
 }
 
 // |SocketBase|
 
 void
 DaemonSocket::Close()
 {
   if (!mIO) {
-    CHROMIUM_LOG("Bluetooth daemon already disconnected!");
+    CHROMIUM_LOG("HAL daemon already disconnected!");
     return;
   }
 
   MOZ_ASSERT(mIO->IsConsumerThread());
 
   mIO->ShutdownOnConsumerThread();
   mIO->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mIO));
   mIO = nullptr;
rename from ipc/bluetooth/BluetoothDaemonConnection.h
rename to ipc/hal/DaemonSocket.h
--- a/ipc/bluetooth/BluetoothDaemonConnection.h
+++ b/ipc/hal/DaemonSocket.h
@@ -1,123 +1,30 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_ipc_bluetooth_DaemonSocket_h
-#define mozilla_ipc_bluetooth_DaemonSocket_h
+#ifndef mozilla_ipc_DaemonSocket_h
+#define mozilla_ipc_DaemonSocket_h
 
-#include "mozilla/Attributes.h"
-#include "mozilla/FileUtils.h"
 #include "mozilla/ipc/ConnectionOrientedSocket.h"
-#include "nsAutoPtr.h"
-
-class MessageLoop;
 
 namespace mozilla {
 namespace ipc {
 
 class DaemonSocketConsumer;
 class DaemonSocketIO;
 class DaemonSocketIOConsumer;
 
-/*
- * |DaemonSocketPDU| represents a single PDU that is transfered from or to
- * the Bluetooth daemon. Each PDU contains exactly one command.
- *
- * A PDU as the following format
- *
- *    |    1    |    1    |        2       |    n    |
- *    | service |  opcode | payload length | payload |
- *
- * Service and Opcode each require 1 byte, the payload length requires 2
- * bytes, and the payload requires the number of bytes as stored in the
- * payload-length field.
- *
- * Each service and opcode can have a different payload with individual
- * length. For the exact details of the Bluetooth protocol, please refer
- * to
- *
- *    https://git.kernel.org/cgit/bluetooth/bluez.git/tree/android/hal-ipc-api.txt?id=5.24
- *
- */
-class DaemonSocketPDU final : public UnixSocketIOBuffer
-{
-public:
-  enum {
-    OFF_SERVICE = 0,
-    OFF_OPCODE = 1,
-    OFF_LENGTH = 2,
-    OFF_PAYLOAD = 4,
-    HEADER_SIZE = OFF_PAYLOAD,
-    MAX_PAYLOAD_LENGTH = 1 << 16
-  };
-
-  DaemonSocketPDU(uint8_t aService, uint8_t aOpcode,
-                     uint16_t aPayloadSize);
-  DaemonSocketPDU(size_t aPayloadSize);
-  ~DaemonSocketPDU();
-
-  void SetConsumer(DaemonSocketIOConsumer* aConsumer)
-  {
-    mConsumer = aConsumer;
-  }
-
-  void SetUserData(void* aUserData)
-  {
-    mUserData = aUserData;
-  }
-
-  void* GetUserData() const
-  {
-    return mUserData;
-  }
-
-  void GetHeader(uint8_t& aService, uint8_t& aOpcode,
-                 uint16_t& aPayloadSize);
-
-  ssize_t Send(int aFd) override;
-  ssize_t Receive(int aFd) override;
-
-  int AcquireFd();
-
-  nsresult UpdateHeader();
-
-private:
-  size_t GetPayloadSize() const;
-  void OnError(const char* aFunction, int aErrno);
-
-  DaemonSocketIOConsumer* mConsumer;
-  void* mUserData;
-  ScopedClose mReceivedFd;
-};
-
-/*
- * |DaemonSocketIOConsumer| processes incoming PDUs from the Bluetooth
- * daemon. Please note that its method |Handle| runs on a different than the
- * consumer thread.
- */
-class DaemonSocketIOConsumer
-{
-public:
-  virtual ~DaemonSocketIOConsumer();
-
-  virtual void Handle(DaemonSocketPDU& aPDU) = 0;
-  virtual void StoreUserData(const DaemonSocketPDU& aPDU) = 0;
-
-protected:
-  DaemonSocketIOConsumer();
-};
-
-/*
- * |DaemonSocket| represents the socket to connect to the
- * Bluetooth daemon. It offers connection establishment and sending
- * PDUs. PDU receiving is performed by |DaemonSocketIOConsumer|.
+/**
+ * |DaemonSocket| represents the socket to connect to the HAL daemon. It
+ * offers connection establishment and sending PDUs. PDU receiving is
+ * performed by |DaemonSocketIOConsumer|.
  */
 class DaemonSocket : public ConnectionOrientedSocket
 {
 public:
   DaemonSocket(DaemonSocketIOConsumer* aIOConsumer,
                DaemonSocketConsumer* aConsumer,
                int aIndex);
   virtual ~DaemonSocket();
rename from ipc/bluetooth/BluetoothDaemonConnectionConsumer.cpp
rename to ipc/hal/DaemonSocketConsumer.cpp
--- a/ipc/bluetooth/BluetoothDaemonConnectionConsumer.cpp
+++ b/ipc/hal/DaemonSocketConsumer.cpp
@@ -1,20 +1,30 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "BluetoothDaemonConnectionConsumer.h"
+#include "DaemonSocketConsumer.h"
 
 namespace mozilla {
 namespace ipc {
 
 //
+// DaemonSocketIOConsumer
+//
+
+DaemonSocketIOConsumer::DaemonSocketIOConsumer()
+{ }
+
+DaemonSocketIOConsumer::~DaemonSocketIOConsumer()
+{ }
+
+//
 // DaemonSocketConsumer
 //
 
 DaemonSocketConsumer::DaemonSocketConsumer()
 { }
 
 DaemonSocketConsumer::~DaemonSocketConsumer()
 { }
rename from ipc/bluetooth/BluetoothDaemonConnectionConsumer.h
rename to ipc/hal/DaemonSocketConsumer.h
--- a/ipc/bluetooth/BluetoothDaemonConnectionConsumer.h
+++ b/ipc/hal/DaemonSocketConsumer.h
@@ -1,26 +1,40 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_ipc_BluetoothDaemonConnectionConsumer_h
-#define mozilla_ipc_BluetoothDaemonConnectionConsumer_h
-
-#include "mozilla/Attributes.h"
-#include "mozilla/FileUtils.h"
-#include "mozilla/ipc/ConnectionOrientedSocket.h"
-#include "nsAutoPtr.h"
+#ifndef mozilla_ipc_DaemonSocketConsumer_h
+#define mozilla_ipc_DaemonSocketConsumer_h
 
 namespace mozilla {
 namespace ipc {
 
-/*
+class DaemonSocketPDU;
+
+/**
+ * |DaemonSocketIOConsumer| processes incoming PDUs from the
+ * HAL daemon. Please note that its method |Handle| runs on a
+ * different than the  consumer thread.
+ */
+class DaemonSocketIOConsumer
+{
+public:
+  virtual ~DaemonSocketIOConsumer();
+
+  virtual void Handle(DaemonSocketPDU& aPDU) = 0;
+  virtual void StoreUserData(const DaemonSocketPDU& aPDU) = 0;
+
+protected:
+  DaemonSocketIOConsumer();
+};
+
+/**
  * |DaemonSocketConsumer| handles socket events.
  */
 class DaemonSocketConsumer
 {
 public:
   /**
    * Callback for socket success. Consumer-thread only.
    *
new file mode 100644
--- /dev/null
+++ b/ipc/hal/DaemonSocketPDU.cpp
@@ -0,0 +1,188 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DaemonSocketPDU.h"
+#include "mozilla/ipc/DaemonSocketConsumer.h"
+
+#ifdef CHROMIUM_LOG
+#undef CHROMIUM_LOG
+#endif
+
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "I/O", args);
+#else
+#include <stdio.h>
+#define IODEBUG true
+#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
+#endif
+
+namespace mozilla {
+namespace ipc {
+
+//
+// DaemonSocketPDU
+//
+
+DaemonSocketPDU::DaemonSocketPDU(uint8_t aService, uint8_t aOpcode,
+                                       uint16_t aPayloadSize)
+  : mConsumer(nullptr)
+  , mUserData(nullptr)
+{
+  // Allocate memory
+  size_t availableSpace = HEADER_SIZE + aPayloadSize;
+  ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace);
+
+  // Reserve PDU header
+  uint8_t* data = Append(HEADER_SIZE);
+  MOZ_ASSERT(data);
+
+  // Setup PDU header
+  data[OFF_SERVICE] = aService;
+  data[OFF_OPCODE] = aOpcode;
+  memcpy(data + OFF_LENGTH, &aPayloadSize, sizeof(aPayloadSize));
+}
+
+DaemonSocketPDU::DaemonSocketPDU(size_t aPayloadSize)
+  : mConsumer(nullptr)
+  , mUserData(nullptr)
+{
+  size_t availableSpace = HEADER_SIZE + aPayloadSize;
+  ResetBuffer(new uint8_t[availableSpace], 0, 0, availableSpace);
+}
+
+DaemonSocketPDU::~DaemonSocketPDU()
+{
+  nsAutoArrayPtr<uint8_t> data(GetBuffer());
+  ResetBuffer(nullptr, 0, 0, 0);
+}
+
+void
+DaemonSocketPDU::GetHeader(uint8_t& aService, uint8_t& aOpcode,
+                              uint16_t& aPayloadSize)
+{
+  memcpy(&aService, GetData(OFF_SERVICE), sizeof(aService));
+  memcpy(&aOpcode, GetData(OFF_OPCODE), sizeof(aOpcode));
+  memcpy(&aPayloadSize, GetData(OFF_LENGTH), sizeof(aPayloadSize));
+}
+
+ssize_t
+DaemonSocketPDU::Send(int aFd)
+{
+  struct iovec iv;
+  memset(&iv, 0, sizeof(iv));
+  iv.iov_base = GetData(GetLeadingSpace());
+  iv.iov_len = GetSize();
+
+  struct msghdr msg;
+  memset(&msg, 0, sizeof(msg));
+  msg.msg_iov = &iv;
+  msg.msg_iovlen = 1;
+  msg.msg_control = nullptr;
+  msg.msg_controllen = 0;
+
+  ssize_t res = TEMP_FAILURE_RETRY(sendmsg(aFd, &msg, 0));
+  if (res < 0) {
+    MOZ_ASSERT(errno != EBADF); /* internal error */
+    OnError("sendmsg", errno);
+    return -1;
+  }
+
+  Consume(res);
+
+  if (mConsumer) {
+    // We successfully sent a PDU, now store the
+    // result runnable in the consumer.
+    mConsumer->StoreUserData(*this);
+  }
+
+  return res;
+}
+
+#define CMSGHDR_CONTAINS_FD(_cmsghdr) \
+    ( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \
+      ((_cmsghdr)->cmsg_type == SCM_RIGHTS) )
+
+ssize_t
+DaemonSocketPDU::Receive(int aFd)
+{
+  struct iovec iv;
+  memset(&iv, 0, sizeof(iv));
+  iv.iov_base = GetData(0);
+  iv.iov_len = GetAvailableSpace();
+
+  uint8_t cmsgbuf[CMSG_SPACE(sizeof(int))];
+
+  struct msghdr msg;
+  memset(&msg, 0, sizeof(msg));
+  msg.msg_iov = &iv;
+  msg.msg_iovlen = 1;
+  msg.msg_control = cmsgbuf;
+  msg.msg_controllen = sizeof(cmsgbuf);
+
+  ssize_t res = TEMP_FAILURE_RETRY(recvmsg(aFd, &msg, MSG_NOSIGNAL));
+  if (res < 0) {
+    MOZ_ASSERT(errno != EBADF); /* internal error */
+    OnError("recvmsg", errno);
+    return -1;
+  }
+  if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) {
+    return -1;
+  }
+
+  SetRange(0, res);
+
+  struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg);
+
+  for (; chdr; chdr = CMSG_NXTHDR(&msg, chdr)) {
+    if (NS_WARN_IF(!CMSGHDR_CONTAINS_FD(chdr))) {
+      continue;
+    }
+    // Retrieve sent file descriptor. If multiple file descriptors
+    // have been sent, we close all but the final one.
+    mReceivedFd = *(static_cast<int*>(CMSG_DATA(chdr)));
+  }
+
+  return res;
+}
+
+int
+DaemonSocketPDU::AcquireFd()
+{
+  return mReceivedFd.forget();
+}
+
+nsresult
+DaemonSocketPDU::UpdateHeader()
+{
+  size_t len = GetPayloadSize();
+  if (len >= MAX_PAYLOAD_LENGTH) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  uint16_t len16 = static_cast<uint16_t>(len);
+
+  memcpy(GetData(OFF_LENGTH), &len16, sizeof(len16));
+
+  return NS_OK;
+}
+
+size_t
+DaemonSocketPDU::GetPayloadSize() const
+{
+  MOZ_ASSERT(GetSize() >= HEADER_SIZE);
+
+  return GetSize() - HEADER_SIZE;
+}
+
+void
+DaemonSocketPDU::OnError(const char* aFunction, int aErrno)
+{
+  CHROMIUM_LOG("%s failed with error %d (%s)",
+               aFunction, aErrno, strerror(aErrno));
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/hal/DaemonSocketPDU.h
@@ -0,0 +1,91 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ipc_DaemonSocketPDU_h
+#define mozilla_ipc_DaemonSocketPDU_h
+
+#include "mozilla/FileUtils.h"
+#include "mozilla/ipc/SocketBase.h"
+
+namespace mozilla {
+namespace ipc {
+
+class DaemonSocketIOConsumer;
+
+/**
+ * |DaemonSocketPDU| represents a single PDU that is transfered from or to
+ * the HAL daemon. Each PDU contains exactly one command.
+ *
+ * A PDU as the following format
+ *
+ *    |    1    |    1    |        2       |    n    |
+ *    | service |  opcode | payload length | payload |
+ *
+ * Service and Opcode each require 1 byte, the payload length requires 2
+ * bytes, and the payload requires the number of bytes as stored in the
+ * payload-length field.
+ *
+ * Each service and opcode can have a different payload with individual
+ * length. For the exact details of the HAL protocol, please refer to
+ *
+ *    https://git.kernel.org/cgit/bluetooth/bluez.git/tree/android/hal-ipc-api.txt?id=5.24
+ *
+ */
+class DaemonSocketPDU final : public UnixSocketIOBuffer
+{
+public:
+  enum {
+    OFF_SERVICE = 0,
+    OFF_OPCODE = 1,
+    OFF_LENGTH = 2,
+    OFF_PAYLOAD = 4,
+    HEADER_SIZE = OFF_PAYLOAD,
+    MAX_PAYLOAD_LENGTH = 1 << 16
+  };
+
+  DaemonSocketPDU(uint8_t aService, uint8_t aOpcode, uint16_t aPayloadSize);
+  DaemonSocketPDU(size_t aPayloadSize);
+  ~DaemonSocketPDU();
+
+  void SetConsumer(DaemonSocketIOConsumer* aConsumer)
+  {
+    mConsumer = aConsumer;
+  }
+
+  void SetUserData(void* aUserData)
+  {
+    mUserData = aUserData;
+  }
+
+  void* GetUserData() const
+  {
+    return mUserData;
+  }
+
+  void GetHeader(uint8_t& aService, uint8_t& aOpcode,
+                 uint16_t& aPayloadSize);
+
+  ssize_t Send(int aFd) override;
+  ssize_t Receive(int aFd) override;
+
+  int AcquireFd();
+
+  nsresult UpdateHeader();
+
+private:
+  size_t GetPayloadSize() const;
+  void OnError(const char* aFunction, int aErrno);
+
+  DaemonSocketIOConsumer* mConsumer;
+  void* mUserData;
+  ScopedClose mReceivedFd;
+};
+
+}
+}
+
+#endif
+
rename from ipc/bluetooth/moz.build
rename to ipc/hal/moz.build
--- a/ipc/bluetooth/moz.build
+++ b/ipc/hal/moz.build
@@ -1,21 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS.mozilla.ipc += [
-    'BluetoothDaemonConnection.h',
-    'BluetoothDaemonConnectionConsumer.h'
+    'DaemonSocket.h',
+    'DaemonSocketConsumer.h',
+    'DaemonSocketPDU.h'
 ]
 
-SOURCES += [
-    'BluetoothDaemonConnection.cpp',
-    'BluetoothDaemonConnectionConsumer.cpp'
+UNIFIED_SOURCES += [
+    'DaemonSocket.cpp',
+    'DaemonSocketConsumer.cpp',
+    'DaemonSocketPDU.cpp'
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
--- a/ipc/moz.build
+++ b/ipc/moz.build
@@ -9,27 +9,24 @@ DIRS += [
     'glue',
     'ipdl',
     'testshell',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     DIRS += ['ril']
 
-if CONFIG['MOZ_B2G_BT_BLUEDROID']:
-    DIRS += ['bluetooth']
-
 if CONFIG['MOZ_B2G_BT_BLUEZ']:
     DIRS += ['dbus']
 
 if CONFIG['MOZ_NFC']:
     DIRS += ['nfc']
 
 if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT'] or CONFIG['MOZ_NFC'] or CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += ['unixfd', 'unixsocket']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    DIRS += ['keystore', 'netd']
+    DIRS += ['hal', 'keystore', 'netd']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
     DIRS += ['contentproc']
 
 DIRS += ['app']