Log pthread_create() errors in MDNS listener

Test: as follows
    - built (bullhead)
    - flashed
    - booted
    - runtest -x netd_integration_test.cpp passed

Bug: 35909721
Change-Id: I09cc05955f88337901ec42f01ccfbd7c27677928
diff --git a/server/DnsProxyListener.cpp b/server/DnsProxyListener.cpp
index 59a85f0..b101d24 100644
--- a/server/DnsProxyListener.cpp
+++ b/server/DnsProxyListener.cpp
@@ -46,6 +46,7 @@
 #include "NetworkController.h"
 #include "ResponseCode.h"
 #include "Stopwatch.h"
+#include "thread_util.h"
 #include "android/net/metrics/INetdEventListener.h"
 
 using android::String16;
@@ -57,43 +58,6 @@
 namespace {
 
 template<typename T>
-void* threadMain(void* obj) {
-    std::unique_ptr<T> handler(reinterpret_cast<T*>(obj));
-    handler->run();
-    return nullptr;
-}
-
-struct scoped_pthread_attr {
-    scoped_pthread_attr() { pthread_attr_init(&attr); }
-    ~scoped_pthread_attr() { pthread_attr_destroy(&attr); }
-
-    int detach() {
-        return pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-    }
-
-    pthread_attr_t attr;
-};
-
-template<typename T>
-int threadLaunch(T* self) {
-    if (self == nullptr) { return -EINVAL;}
-
-    scoped_pthread_attr scoped_attr;
-
-    int rval = scoped_attr.detach();
-    if (rval != 0) { return -errno; }
-
-    pthread_t thread;
-    rval = pthread_create(&thread, &scoped_attr.attr, &threadMain<T>, self);
-    if (rval != 0) {
-        ALOGW("pthread_create failed: %d", errno);
-        return -errno;
-    }
-
-    return rval;
-}
-
-template<typename T>
 void tryThreadOrError(SocketClient* cli, T* handler) {
     cli->incRef();
 
diff --git a/server/MDnsSdListener.cpp b/server/MDnsSdListener.cpp
index 883fe81..9551d45 100644
--- a/server/MDnsSdListener.cpp
+++ b/server/MDnsSdListener.cpp
@@ -38,6 +38,7 @@
 
 #include "MDnsSdListener.h"
 #include "ResponseCode.h"
+#include "thread_util.h"
 
 #define MDNS_SERVICE_NAME "mdnsd"
 #define MDNS_SERVICE_STATUS "init.svc.mdnsd"
@@ -524,17 +525,10 @@
     socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair);
     pthread_mutex_init(&mHeadMutex, NULL);
 
-    pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this);
-    pthread_detach(mThread);
-}
-
-void *MDnsSdListener::Monitor::threadStart(void *obj) {
-    Monitor *monitor = reinterpret_cast<Monitor *>(obj);
-
-    monitor->run();
-    delete monitor;
-    pthread_exit(NULL);
-    return NULL;
+    const int rval = ::android::net::threadLaunch(this);
+    if (rval != 0) {
+        ALOGW("Error spawning monitor thread: %s (%d)", strerror(-rval), -rval);
+    }
 }
 
 #define NAP_TIME 200  // 200 ms between polls
diff --git a/server/MDnsSdListener.h b/server/MDnsSdListener.h
index e9c6066..3833ad6 100644
--- a/server/MDnsSdListener.h
+++ b/server/MDnsSdListener.h
@@ -65,6 +65,7 @@
         }
     };
 
+private:
     class Monitor {
     public:
         Monitor();
@@ -73,11 +74,11 @@
         void startMonitoring(int id);
         DNSServiceRef *lookupServiceRef(int id);
         void freeServiceRef(int id);
-        static void *threadStart(void *handler);
         int startService();
         int stopService();
-    private:
         void run();
+
+    private:
         int rescan(); // returns the number of elements in the poll
         class Element {
         public:
@@ -95,7 +96,6 @@
         struct pollfd *mPollFds;
         DNSServiceRef **mPollRefs;
         int mPollSize;
-        pthread_t mThread;
         int mCtrlSocketPair[2];
         pthread_mutex_t mHeadMutex;
     };
diff --git a/server/thread_util.h b/server/thread_util.h
new file mode 100644
index 0000000..8a7ea6f
--- /dev/null
+++ b/server/thread_util.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef NETD_SERVER_THREAD_UTIL_H
+#define NETD_SERVER_THREAD_UTIL_H
+
+#include <pthread.h>
+#include <memory>
+
+namespace android {
+namespace net {
+
+struct scoped_pthread_attr {
+    scoped_pthread_attr() { pthread_attr_init(&attr); }
+    ~scoped_pthread_attr() { pthread_attr_destroy(&attr); }
+
+    int detach() {
+        return pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    }
+
+    pthread_attr_t attr;
+};
+
+template<typename T>
+inline void* runAndDelete(void* obj) {
+    std::unique_ptr<T> handler(reinterpret_cast<T*>(obj));
+    handler->run();
+    return nullptr;
+}
+
+template<typename T>
+inline int threadLaunch(T* obj) {
+    if (obj == nullptr) { return -EINVAL;}
+
+    scoped_pthread_attr scoped_attr;
+
+    int rval = scoped_attr.detach();
+    if (rval != 0) { return -errno; }
+
+    pthread_t thread;
+    rval = pthread_create(&thread, &scoped_attr.attr, &runAndDelete<T>, obj);
+    if (rval != 0) {
+        ALOGW("pthread_create failed: %d", errno);
+        return -errno;
+    }
+
+    return rval;
+}
+
+}  // namespace net
+}  // namespace android
+
+#endif  // NETD_SERVER_THREAD_UTIL_H