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 id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1171017
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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']