Provide --android-ipc-socket-suffix.

This allows Android init to create a socket
for the service, and have consolidated access control.

Android init creates the socket and passes the FD through
an environment variable, so we must use OSI to decode it.

Bug: 22807533
Change-Id: I7ec0a14b8f3b44277ce99faad68623d6691f7863
diff --git a/service/daemon.cpp b/service/daemon.cpp
index a88fc5f..2f35356 100644
--- a/service/daemon.cpp
+++ b/service/daemon.cpp
@@ -92,9 +92,9 @@
 
   ipc_manager_.reset(new ipc::IPCManager(core_stack_.get()));
 
-  // If an IPC socket path was given, initialize the UNIX domain socket based
-  // IPC layer.
-  if (!settings_->ipc_socket_path().empty() &&
+  // If an IPC socket path was given, initialize IPC with it.
+  if ((!settings_->create_ipc_socket_path().empty() ||
+       !settings_->android_ipc_socket_suffix().empty()) &&
       !ipc_manager_->Start(ipc::IPCManager::TYPE_UNIX)) {
     LOG(ERROR) << "Failed to set up UNIX domain-socket IPCManager";
     return false;
diff --git a/service/ipc/ipc_handler_unix.cpp b/service/ipc/ipc_handler_unix.cpp
index 37df848..a051c96 100644
--- a/service/ipc/ipc_handler_unix.cpp
+++ b/service/ipc/ipc_handler_unix.cpp
@@ -21,6 +21,7 @@
 
 #include <base/bind.h>
 
+#include "osi/include/socket_utils/sockets.h"
 #include "service/daemon.h"
 #include "service/ipc/unix_ipc_host.h"
 #include "service/settings.h"
@@ -39,9 +40,14 @@
 bool IPCHandlerUnix::Run() {
   CHECK(!running_);
 
+  const std::string& android_suffix =
+      bluetooth::Daemon::Get()->settings()->android_ipc_socket_suffix();
   const base::FilePath& path =
-      bluetooth::Daemon::Get()->settings()->ipc_socket_path();
-  if (path.empty()) {
+      bluetooth::Daemon::Get()->settings()->create_ipc_socket_path();
+
+  // Both flags cannot be set at the same time.
+  CHECK(android_suffix.empty() || path.empty());
+  if (android_suffix.empty() && path.empty()) {
     LOG(ERROR) << "No domain socket path provided";
     return false;
   }
@@ -49,31 +55,47 @@
   CHECK(base::MessageLoop::current());  // An origin event loop is required.
   origin_task_runner_ = base::MessageLoop::current()->task_runner();
 
-  // TODO(armansito): This is opens the door to potentially unlinking files in
-  // the current directory that we're not supposed to. For now we will have an
-  // assumption that the daemon runs in a sandbox but we should generally do
-  // this properly.
-  //
-  // Also, the daemon should clean this up properly as it shuts down.
-  unlink(path.value().c_str());
+  if (!android_suffix.empty()) {
+    int server_fd = osi_android_get_control_socket(android_suffix.c_str());
+    if (server_fd == -1) {
+      LOG(ERROR) << "Unable to get Android socket from: " << android_suffix;
+      return false;
+    }
+    LOG(INFO) << "Binding to Android server socket:" << android_suffix;
+    socket_.reset(server_fd);
+  } else {
+    LOG(INFO) << "Creating a Unix domain socket:" << path.value();
 
-  base::ScopedFD server_socket(socket(PF_UNIX, SOCK_SEQPACKET, 0));
-  if (!server_socket.is_valid()) {
-    LOG(ERROR) << "Failed to open domain socket for IPC";
-    return false;
+    // TODO(armansito): This is opens the door to potentially unlinking files in
+    // the current directory that we're not supposed to. For now we will have an
+    // assumption that the daemon runs in a sandbox but we should generally do
+    // this properly.
+    //
+    // Also, the daemon should clean this up properly as it shuts down.
+    unlink(path.value().c_str());
+
+    base::ScopedFD server_socket(socket(PF_UNIX, SOCK_SEQPACKET, 0));
+    if (!server_socket.is_valid()) {
+      LOG(ERROR) << "Failed to open domain socket for IPC";
+      return false;
+    }
+
+    struct sockaddr_un address;
+    memset(&address, 0, sizeof(address));
+    address.sun_family = AF_UNIX;
+    strncpy(address.sun_path, path.value().c_str(),
+            sizeof(address.sun_path) - 1);
+    if (bind(server_socket.get(), (struct sockaddr*)&address, sizeof(address)) <
+        0) {
+      LOG(ERROR) << "Failed to bind IPC socket to address: " << strerror(errno);
+      return false;
+    }
+
+    socket_.swap(server_socket);
   }
 
-  struct sockaddr_un address;
-  memset(&address, 0, sizeof(address));
-  address.sun_family = AF_UNIX;
-  strncpy(address.sun_path, path.value().c_str(), sizeof(address.sun_path) - 1);
-  if (bind(server_socket.get(), (struct sockaddr*)&address,
-           sizeof(address)) < 0) {
-    LOG(ERROR) << "Failed to bind IPC socket to address: " << strerror(errno);
-    return false;
-  }
+  CHECK(socket_.is_valid());
 
-  socket_.swap(server_socket);
   running_ = true;  // Set this here before launching the thread.
 
   // Start an IO thread and post the listening task.
diff --git a/service/settings.cpp b/service/settings.cpp
index 2558eaa..66235e7 100644
--- a/service/settings.cpp
+++ b/service/settings.cpp
@@ -35,23 +35,39 @@
   const auto& switches = command_line->GetSwitches();
 
   for (const auto& iter : switches) {
-    if (iter.first == switches::kIPCSocketPath) {
-      // kIPCSocketPath: An optional argument that initializes an IPC socket
-      // path for IPC. If this is not present, the daemon will default to Binder
-      // for the IPC mechanism.
+    if (iter.first == switches::kCreateIPCSocketPath) {
+      // kCreateIPCSocketPath: An optional argument that initializes an IPC
+      // socket path for IPC.
       base::FilePath path(iter.second);
       if (path.empty() || path.EndsWithSeparator()) {
-        LOG(ERROR) << "Invalid IPC socket path";
+        LOG(ERROR) << "Invalid IPC create socket path";
         return false;
       }
 
-      ipc_socket_path_ = path;
+      create_ipc_socket_path_ = path;
+    } else if (iter.first == switches::kAndroidIPCSocketSuffix) {
+      // kAndroidIPCSocketSuffix: An optional argument used to express
+      // a socket that Android init created for us. We bind to this.
+      const std::string& suffix = iter.second;
+      if (suffix.empty()) {
+        LOG(ERROR) << "Invalid Android socket suffix";
+        return false;
+      }
+
+      android_ipc_socket_suffix_ = suffix;
     } else {
       LOG(ERROR) << "Unexpected command-line switches found";
       return false;
     }
   }
 
+  // Two IPC methods/paths were provided.
+  if (!android_ipc_socket_suffix_.empty() &&
+      !create_ipc_socket_path_.empty()) {
+    LOG(ERROR) << "Too many IPC methods provided";
+    return false;
+  }
+
   // The daemon has no arguments
   if (command_line->GetArgs().size()) {
     LOG(ERROR) << "Unexpected command-line arguments found";
diff --git a/service/settings.h b/service/settings.h
index 900408c..4747dba 100644
--- a/service/settings.h
+++ b/service/settings.h
@@ -42,17 +42,21 @@
   // if there is an error, e.g. if the parameters/switches are malformed.
   bool Init();
 
-  // Path to the unix domain socket for Bluetooth IPC. On Android, this needs to
-  // match the init provided socket domain prefix. Outside Android, this will be
-  // the path for the traditional Unix domain socket that the daemon will
-  // create.
-  const base::FilePath& ipc_socket_path() const {
-    return ipc_socket_path_;
+  // If Android init created a server socket for the daemon,
+  // we can retrieve it through this suffix.
+  const std::string& android_ipc_socket_suffix() const {
+    return android_ipc_socket_suffix_;
+  }
+
+  // Path to create a Unix domain socket server for Bluetooth IPC.
+  const base::FilePath& create_ipc_socket_path() const {
+    return create_ipc_socket_path_;
   }
 
  private:
   bool initialized_;
-  base::FilePath ipc_socket_path_;
+  std::string android_ipc_socket_suffix_;
+  base::FilePath create_ipc_socket_path_;
 
   DISALLOW_COPY_AND_ASSIGN(Settings);
 };
diff --git a/service/switches.h b/service/switches.h
index 424f266..755b4d2 100644
--- a/service/switches.h
+++ b/service/switches.h
@@ -24,14 +24,18 @@
 // List of command-line switches used by the daemon.
 const char kHelpLong[] = "help";
 const char kHelpShort[] = "h";
-const char kIPCSocketPath[] = "ipc-socket";
+const char kAndroidIPCSocketSuffix[] = "android-ipc-socket-suffix";
+const char kCreateIPCSocketPath[] = "create-ipc-socket";
 
 const char kHelpMessage[] =
     "\nBluetooth System Service\n"
     "\n"
     "Usage:\n"
     "\t--help,-h\tShow this help message\n"
-    "\t--ipc-socket\tSocket path used for domain socket based IPC";
+    "\t--android-ipc-socket-suffix\tSuffix of socket created by Android init. "
+    "Mutually exclusive with --create-ipc-socket.\n"
+    "\t--create-ipc-socket\tSocket path created for Unix domain socket based "
+    "IPC. Mutually exclusive with --android-ipc-socket-suffix.";
 
 }  // namespace switches
 }  // namespace bluetooth
diff --git a/service/test/settings_unittest.cpp b/service/test/settings_unittest.cpp
index fa47c37..c06861c 100644
--- a/service/test/settings_unittest.cpp
+++ b/service/test/settings_unittest.cpp
@@ -51,7 +51,7 @@
 
 TEST_F(SettingsTest, UnexpectedSwitches1) {
   const base::CommandLine::CharType* argv[] = {
-    "program", "--ipc-socket-path=foobar", "--foobarbaz"
+    "program", "--create-ipc-socket=foobar", "--foobarbaz"
   };
   base::CommandLine::Init(arraysize(argv), argv);
   EXPECT_FALSE(settings_.Init());
@@ -75,15 +75,31 @@
 
 TEST_F(SettingsTest, UnexpectedArguments2) {
   const base::CommandLine::CharType* argv[] = {
-    "program", "--ipc-socket-path=foobar", "foobarbaz"
+    "program", "--create-ipc-socket=foobar", "foobarbaz"
   };
   base::CommandLine::Init(arraysize(argv), argv);
   EXPECT_FALSE(settings_.Init());
 }
 
-TEST_F(SettingsTest, GoodArguments) {
+TEST_F(SettingsTest, TooManyIpcOptions) {
   const base::CommandLine::CharType* argv[] = {
-    "program", "--ipc-socket=foobar"
+      "program", "--create-ipc-socket=foobar",
+      "--android-ipc-socket-suffix=foobar"};
+  base::CommandLine::Init(arraysize(argv), argv);
+  EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, GoodArgumentsCreateIpc) {
+  const base::CommandLine::CharType* argv[] = {
+    "program", "--create-ipc-socket=foobar"
+  };
+  base::CommandLine::Init(arraysize(argv), argv);
+  EXPECT_TRUE(settings_.Init());
+}
+
+TEST_F(SettingsTest, GoodArgumentsAndroidIpc) {
+  const base::CommandLine::CharType* argv[] = {
+    "program", "--android-ipc-socket-suffix=foobar"
   };
   base::CommandLine::Init(arraysize(argv), argv);
   EXPECT_TRUE(settings_.Init());