OSDN Git Service

DO NOT MERGE Move Stopwatch into its own header
[android-x86/system-netd.git] / server / DnsProxyListener.cpp
index a0f0a30..2a5ecc0 100644 (file)
@@ -18,6 +18,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <linux/if.h>
+#include <math.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <stdlib.h>
 #define DBG 0
 #define VDBG 0
 
+#include <chrono>
+
 #include <cutils/log.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
 #include <sysutils/SocketClient.h>
 
 #include "Fwmark.h"
 #include "NetdConstants.h"
 #include "NetworkController.h"
 #include "ResponseCode.h"
+#include "Stopwatch.h"
+#include "android/net/metrics/INetdEventListener.h"
+
+using android::String16;
+using android::interface_cast;
+using android::net::metrics::INetdEventListener;
 
 DnsProxyListener::DnsProxyListener(const NetworkController* netCtrl) :
         FrameworkListener("dnsproxyd"), mNetCtrl(netCtrl) {
@@ -48,18 +59,16 @@ DnsProxyListener::DnsProxyListener(const NetworkController* netCtrl) :
     registerCmd(new GetHostByNameCmd(this));
 }
 
-DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(SocketClient *c,
-                                                         char* host,
-                                                         char* service,
-                                                         struct addrinfo* hints,
-                                                         unsigned netId,
-                                                         uint32_t mark)
+DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(
+        SocketClient *c, char* host, char* service, struct addrinfo* hints,
+        const struct android_net_context& netcontext,
+        const android::sp<android::net::metrics::INetdEventListener>& netdEventListener)
         : mClient(c),
           mHost(host),
           mService(service),
           mHints(hints),
-          mNetId(netId),
-          mMark(mark) {
+          mNetContext(netcontext),
+          mNetdEventListener(netdEventListener) {
 }
 
 DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() {
@@ -83,6 +92,25 @@ void* DnsProxyListener::GetAddrInfoHandler::threadStart(void* obj) {
     return NULL;
 }
 
+android::sp<INetdEventListener> DnsProxyListener::getNetdEventListener() {
+    if (mNetdEventListener == nullptr) {
+        // Use checkService instead of getService because getService waits for 5 seconds for the
+        // service to become available. The DNS resolver inside netd is started much earlier in the
+        // boot sequence than the framework DNS listener, and we don't want to delay all DNS lookups
+        // for 5 seconds until the DNS listener starts up.
+        android::sp<android::IBinder> b = android::defaultServiceManager()->checkService(
+                android::String16("netd_listener"));
+        if (b != nullptr) {
+            mNetdEventListener = interface_cast<INetdEventListener>(b);
+        }
+    }
+    // If the DNS listener service is dead, the binder call will just return an error, which should
+    // be fine because the only impact is that we can't log DNS events. In any case, this should
+    // only happen if the system server is going down, which means it will shortly be taking us down
+    // with it.
+    return mNetdEventListener;
+}
+
 static bool sendBE32(SocketClient* c, uint32_t data) {
     uint32_t be_data = htonl(data);
     return c->sendData(&be_data, sizeof(be_data)) == 0;
@@ -160,11 +188,17 @@ static bool sendaddrinfo(SocketClient* c, struct addrinfo* ai) {
 
 void DnsProxyListener::GetAddrInfoHandler::run() {
     if (DBG) {
-        ALOGD("GetAddrInfoHandler, now for %s / %s / %u / %u", mHost, mService, mNetId, mMark);
+        ALOGD("GetAddrInfoHandler, now for %s / %s / {%u,%u,%u,%u,%u}", mHost, mService,
+                mNetContext.app_netid, mNetContext.app_mark,
+                mNetContext.dns_netid, mNetContext.dns_mark,
+                mNetContext.uid);
     }
 
     struct addrinfo* result = NULL;
-    uint32_t rv = android_getaddrinfofornet(mHost, mService, mHints, mNetId, mMark, &result);
+    Stopwatch s;
+    uint32_t rv = android_getaddrinfofornetcontext(mHost, mService, mHints, &mNetContext, &result);
+    const int latencyMs = lround(s.timeTaken());
+
     if (rv) {
         // getaddrinfo failed
         mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
@@ -184,9 +218,14 @@ void DnsProxyListener::GetAddrInfoHandler::run() {
         freeaddrinfo(result);
     }
     mClient->decRef();
+    if (mNetdEventListener != nullptr) {
+        mNetdEventListener->onDnsEvent(mNetContext.dns_netid,
+                                       INetdEventListener::EVENT_GETADDRINFO, (int32_t) rv,
+                                       latencyMs);
+    }
 }
 
-DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd(const DnsProxyListener* dnsProxyListener) :
+DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd(DnsProxyListener* dnsProxyListener) :
     NetdCommand("getaddrinfo"),
     mDnsProxyListener(dnsProxyListener) {
 }
@@ -229,7 +268,8 @@ int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
     unsigned netId = strtoul(argv[7], NULL, 10);
     uid_t uid = cli->getUid();
 
-    uint32_t mark = mDnsProxyListener->mNetCtrl->getNetworkForDns(&netId, uid);
+    struct android_net_context netcontext;
+    mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext);
 
     if (ai_flags != -1 || ai_family != -1 ||
         ai_socktype != -1 || ai_protocol != -1) {
@@ -238,25 +278,21 @@ int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
         hints->ai_family = ai_family;
         hints->ai_socktype = ai_socktype;
         hints->ai_protocol = ai_protocol;
-
-        // Only implement AI_ADDRCONFIG if application is using default network since our
-        // implementation only works on the default network.
-        if ((hints->ai_flags & AI_ADDRCONFIG) &&
-                netId != mDnsProxyListener->mNetCtrl->getDefaultNetwork()) {
-            hints->ai_flags &= ~AI_ADDRCONFIG;
-        }
     }
 
     if (DBG) {
-        ALOGD("GetAddrInfoHandler for %s / %s / %u / %d / %u",
+        ALOGD("GetAddrInfoHandler for %s / %s / {%u,%u,%u,%u,%u}",
              name ? name : "[nullhost]",
              service ? service : "[nullservice]",
-             netId, uid, mark);
+             netcontext.app_netid, netcontext.app_mark,
+             netcontext.dns_netid, netcontext.dns_mark,
+             netcontext.uid);
     }
 
     cli->incRef();
     DnsProxyListener::GetAddrInfoHandler* handler =
-            new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, netId, mark);
+            new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, netcontext,
+                                                     mDnsProxyListener->getNetdEventListener());
     handler->start();
 
     return 0;
@@ -265,7 +301,7 @@ int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
 /*******************************************************
  *                  GetHostByName                      *
  *******************************************************/
-DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd(const DnsProxyListener* dnsProxyListener) :
+DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd(DnsProxyListener* dnsProxyListener) :
       NetdCommand("gethostbyname"),
       mDnsProxyListener(dnsProxyListener) {
 }
@@ -301,22 +337,22 @@ int DnsProxyListener::GetHostByNameCmd::runCommand(SocketClient *cli,
 
     cli->incRef();
     DnsProxyListener::GetHostByNameHandler* handler =
-            new DnsProxyListener::GetHostByNameHandler(cli, name, af, netId, mark);
+            new DnsProxyListener::GetHostByNameHandler(cli, name, af, netId, mark,
+                                                       mDnsProxyListener->getNetdEventListener());
     handler->start();
 
     return 0;
 }
 
-DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(SocketClient* c,
-                                                             char* name,
-                                                             int af,
-                                                             unsigned netId,
-                                                             uint32_t mark)
+DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(
+        SocketClient* c, char* name, int af, unsigned netId, uint32_t mark,
+        const android::sp<android::net::metrics::INetdEventListener>& netdEventListener)
         : mClient(c),
           mName(name),
           mAf(af),
           mNetId(netId),
-          mMark(mark) {
+          mMark(mark),
+          mNetdEventListener(netdEventListener) {
 }
 
 DnsProxyListener::GetHostByNameHandler::~GetHostByNameHandler() {
@@ -343,9 +379,9 @@ void DnsProxyListener::GetHostByNameHandler::run() {
         ALOGD("DnsProxyListener::GetHostByNameHandler::run\n");
     }
 
-    struct hostent* hp;
-
-    hp = android_gethostbynamefornet(mName, mAf, mNetId, mMark);
+    Stopwatch s;
+    struct hostent* hp = android_gethostbynamefornet(mName, mAf, mNetId, mMark);
+    const int latencyMs = lround(s.timeTaken());
 
     if (DBG) {
         ALOGD("GetHostByNameHandler::run gethostbyname errno: %s hp->h_name = %s, name_len = %zu\n",
@@ -366,6 +402,11 @@ void DnsProxyListener::GetHostByNameHandler::run() {
         ALOGW("GetHostByNameHandler: Error writing DNS result to client\n");
     }
     mClient->decRef();
+
+    if (mNetdEventListener != nullptr) {
+        mNetdEventListener->onDnsEvent(mNetId, INetdEventListener::EVENT_GETHOSTBYNAME,
+                                      h_errno, latencyMs);
+    }
 }