Os: add GetControlSocket()

Add the GetControlSocket() method to Os, and
add unit tests for the same.

A "control socket" is a service-specific socket
created by the init daemon, to enable other
processes to talk to a given service.

Bug: 32446680
Test: ./runtests.sh (on angler)
Change-Id: I25ea54f8ab85fafd492ec2953e4e369d64ecd02d
diff --git a/Android.mk b/Android.mk
index ed5ec0a..eabfb24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -39,6 +39,7 @@
     raw_os.cpp
 LOCAL_SHARED_LIBRARIES := \
     libbase \
+    libcutils \
     liblog
 include $(BUILD_STATIC_LIBRARY)
 
@@ -66,5 +67,6 @@
     libwifilogd
 LOCAL_SHARED_LIBRARIES := \
     libbase \
+    libcutils \
     liblog
 include $(BUILD_NATIVE_TEST)
diff --git a/os.cpp b/os.cpp
index ae8caca..ab178c1 100644
--- a/os.cpp
+++ b/os.cpp
@@ -33,10 +33,22 @@
 constexpr auto kMaxNanoSeconds = 1000 * 1000 * 1000 - 1;
 }
 
+constexpr int Os::kInvalidFd;
+
 Os::Os() : raw_os_(new RawOs()) {}
 Os::Os(std::unique_ptr<RawOs> raw_os) : raw_os_(std::move(raw_os)) {}
 Os::~Os() {}
 
+std::tuple<int, Os::Errno> Os::GetControlSocket(
+    const std::string& socket_name) {
+  int sock_fd = raw_os_->GetControlSocket(socket_name.c_str());
+  if (sock_fd < 0) {
+    return {kInvalidFd, errno};
+  } else {
+    return {sock_fd, 0};
+  }
+}
+
 Os::Timestamp Os::GetTimestamp(clockid_t clock_id) const {
   struct timespec now_timespec;
   int failed = raw_os_->ClockGettime(clock_id, &now_timespec);
diff --git a/os.h b/os.h
index ca1e886..31fecbe 100644
--- a/os.h
+++ b/os.h
@@ -21,6 +21,7 @@
 
 #include <cstdint>
 #include <memory>
+#include <string>
 #include <tuple>
 #include <utility>
 
@@ -58,6 +59,12 @@
 
   virtual ~Os();
 
+  // Returns the Android control socket with name |socket_name|. If no such
+  // socket exists, or the init daemon has not provided this process with
+  // access to said socket, returns {kInvalidFd, errno}.
+  virtual std::tuple<int, Errno> GetControlSocket(
+      const std::string& socket_name);
+
   // Returns the current time, as reported by the clock with |clock_id|.
   virtual Timestamp GetTimestamp(clockid_t clock_id) const;
 
diff --git a/raw_os.cpp b/raw_os.cpp
index 26aa1b8..8d08901 100644
--- a/raw_os.cpp
+++ b/raw_os.cpp
@@ -17,6 +17,8 @@
 #include <time.h>
 #include <unistd.h>
 
+#include "cutils/sockets.h"
+
 #include "wifilogd/raw_os.h"
 
 namespace android {
@@ -33,6 +35,10 @@
   return clock_gettime(clock_id, ts);
 }
 
+int RawOs::GetControlSocket(const char* socket_name) {
+  return android_get_control_socket(socket_name);
+}
+
 ssize_t RawOs::Recv(int sockfd, void* buf, size_t buflen, int flags) {
   return recv(sockfd, buf, buflen, flags);
 }
diff --git a/raw_os.h b/raw_os.h
index 6d74b6d..3ba9a0f 100644
--- a/raw_os.h
+++ b/raw_os.h
@@ -38,6 +38,9 @@
   virtual int ClockGettime(clockid_t clock_id,
                            NONNULL struct timespec* tspec) const;
 
+  // See android_get_control_socket().
+  virtual int GetControlSocket(const char* socket_name);
+
   // See recv().
   virtual ssize_t Recv(int sockfd, void* buf, size_t buflen, int flags);
 
diff --git a/tests/mock_os.h b/tests/mock_os.h
index 5a378f3..3e02730 100644
--- a/tests/mock_os.h
+++ b/tests/mock_os.h
@@ -17,6 +17,7 @@
 #ifndef TESTS_MOCK_OS_H_
 #define TESTS_MOCK_OS_H_
 
+#include <string>
 #include <tuple>
 
 #include "android-base/macros.h"
@@ -33,6 +34,8 @@
   ~MockOs() override;
 
   MOCK_CONST_METHOD1(GetTimestamp, Timestamp(clockid_t clock_id));
+  MOCK_METHOD1(GetControlSocket,
+               std::tuple<int, Errno>(const std::string& socket_name));
   MOCK_METHOD3(ReceiveDatagram,
                std::tuple<size_t, Errno>(int fd, void* buf, size_t buflen));
   MOCK_METHOD3(Write, std::tuple<size_t, Os::Errno>(int fd, const void* buf,
diff --git a/tests/mock_raw_os.h b/tests/mock_raw_os.h
index 13149d9..3931cb0 100644
--- a/tests/mock_raw_os.h
+++ b/tests/mock_raw_os.h
@@ -32,6 +32,7 @@
 
   MOCK_CONST_METHOD2(ClockGettime,
                      int(clockid_t clock_id, struct timespec* tspec));
+  MOCK_METHOD1(GetControlSocket, int(const char* socket_name));
   MOCK_METHOD4(Recv, ssize_t(int sockfd, void* buf, size_t buflen, int flags));
   MOCK_METHOD3(Write, ssize_t(int fd, const void* buf, size_t buflen));
 
diff --git a/tests/os_unittest.cpp b/tests/os_unittest.cpp
index 00dea33..e90755a 100644
--- a/tests/os_unittest.cpp
+++ b/tests/os_unittest.cpp
@@ -34,6 +34,7 @@
 using ::testing::SetArgumentPointee;
 using ::testing::SetErrnoAndReturn;
 using ::testing::StrictMock;
+using ::testing::StrEq;
 
 using local_utils::GetMaxVal;
 
@@ -53,6 +54,26 @@
 
 }  // namespace
 
+TEST_F(OsTest, GetControlSocketReturnsFdAndZeroOnSuccess) {
+  constexpr char kSocketName[] = "fake-daemon";
+  constexpr int kFakeValidFd = 100;
+  EXPECT_CALL(*raw_os_, GetControlSocket(StrEq(kSocketName)))
+      .WillOnce(Return(kFakeValidFd));
+
+  constexpr std::tuple<int, Os::Errno> kExpectedResult{kFakeValidFd, 0};
+  EXPECT_EQ(kExpectedResult, os_->GetControlSocket(kSocketName));
+}
+
+TEST_F(OsTest, GetControlSocketReturnsInvalidFdAndErrorOnFailure) {
+  constexpr char kSocketName[] = "fake-daemon";
+  constexpr Os::Errno kError = EINVAL;
+  EXPECT_CALL(*raw_os_, GetControlSocket(StrEq(kSocketName)))
+      .WillOnce(SetErrnoAndReturn(kError, -1));
+
+  constexpr std::tuple<int, Os::Errno> kExpectedResult{Os::kInvalidFd, kError};
+  EXPECT_EQ(kExpectedResult, os_->GetControlSocket(kSocketName));
+}
+
 TEST_F(OsTest, GetTimestampSucceeds) {
   constexpr auto kFakeSecs = 1U;
   constexpr auto kFakeNsecs = 2U;