Add connect event reporting
Adds reporting of connect events including netId, destination IP address,
destination port, uid and connect latency.
Also enables the relevant tests in the connect_benchmark.
Currently ignores the new data it receives, further work will be
done in the subsequent CLs.
Test: for now just the benchmarking, in the future CTS
Bug: 29748723
(cherry picked from commit 4b9b78aa02336de9291e5085401cef44c03c3bba)
Change-Id: If8e5ddcd2d29271e2f63a3338a3daf83e7afccdc
diff --git a/server/EventReporter.cpp b/server/EventReporter.cpp
index fd09b8a..c9238f4 100644
--- a/server/EventReporter.cpp
+++ b/server/EventReporter.cpp
@@ -37,6 +37,7 @@
}
android::sp<INetdEventListener> EventReporter::getNetdEventListener() {
+ std::lock_guard<std::mutex> lock(mutex);
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
diff --git a/server/EventReporter.h b/server/EventReporter.h
index cc0e912..3338a04 100644
--- a/server/EventReporter.h
+++ b/server/EventReporter.h
@@ -19,6 +19,7 @@
#include <atomic>
#include <binder/IServiceManager.h>
+#include <mutex>
#include "android/net/metrics/INetdEventListener.h"
@@ -31,16 +32,20 @@
int getMetricsReportingLevel() const;
// Returns the binder reference to the netd events listener service, attempting to fetch it if
- // we do not have it already. This method mutates internal state without taking a lock and must
- // only be called on one thread. This is safe because we only call this in the runCommand
- // methods of our commands, which are only called by FrameworkListener::onDataAvailable, which
- // is only called from SocketListener::runListener, which is a single-threaded select loop.
+ // we do not have it already. This method is threadsafe.
android::sp<android::net::metrics::INetdEventListener> getNetdEventListener();
private:
std::atomic_int mReportingLevel{
android::net::metrics::INetdEventListener::REPORTING_LEVEL_FULL};
+ // TODO: consider changing this into an atomic type such as
+ // std::atomic<android::net::metrics::INetdEventListener> and deleting the mutex.
+ //
+ // Alternatively, if this locking causes a performance penalty, have each single-threaded
+ // caller (DnsProxyListener, FwmarkServer) keep their own per-thread copy of NetdEventListener
+ // and remove mNetdEventListener entirely.
android::sp<android::net::metrics::INetdEventListener> mNetdEventListener;
+ std::mutex mutex;
};
diff --git a/server/FwmarkServer.cpp b/server/FwmarkServer.cpp
index 530e96a..de129ab 100644
--- a/server/FwmarkServer.cpp
+++ b/server/FwmarkServer.cpp
@@ -18,14 +18,20 @@
#include "Fwmark.h"
#include "FwmarkCommand.h"
+#include "NetdConstants.h"
#include "NetworkController.h"
#include "resolv_netid.h"
#include <sys/socket.h>
#include <unistd.h>
+#include <utils/String16.h>
-FwmarkServer::FwmarkServer(NetworkController* networkController) :
- SocketListener("fwmarkd", true), mNetworkController(networkController) {
+using android::String16;
+using android::net::metrics::INetdEventListener;
+
+FwmarkServer::FwmarkServer(NetworkController* networkController, EventReporter* eventReporter) :
+ SocketListener("fwmarkd", true), mNetworkController(networkController),
+ mEventReporter(eventReporter) {
}
bool FwmarkServer::onDataAvailable(SocketClient* client) {
@@ -47,15 +53,16 @@
int FwmarkServer::processClient(SocketClient* client, int* socketFd) {
FwmarkCommand command;
+ FwmarkConnectInfo connectInfo;
- iovec iov;
- iov.iov_base = &command;
- iov.iov_len = sizeof(command);
-
+ iovec iov[2] = {
+ { &command, sizeof(command) },
+ { &connectInfo, sizeof(connectInfo) },
+ };
msghdr message;
memset(&message, 0, sizeof(message));
- message.msg_iov = &iov;
- message.msg_iovlen = 1;
+ message.msg_iov = iov;
+ message.msg_iovlen = ARRAY_SIZE(iov);
union {
cmsghdr cmh;
@@ -71,7 +78,9 @@
return -errno;
}
- if (messageLength != sizeof(command)) {
+ if (!((command.cmdId != FwmarkCommand::ON_CONNECT_COMPLETE && messageLength == sizeof(command))
+ || (command.cmdId == FwmarkCommand::ON_CONNECT_COMPLETE
+ && messageLength == sizeof(command) + sizeof(connectInfo)))) {
return -EBADMSG;
}
@@ -152,6 +161,27 @@
break;
}
+ case FwmarkCommand::ON_CONNECT_COMPLETE: {
+ // Called after a socket connect() completes.
+ // This reports connect event including netId, destination IP address, destination port,
+ // uid and connect latency
+ android::sp<android::net::metrics::INetdEventListener> netdEventListener =
+ mEventReporter->getNetdEventListener();
+
+ if (netdEventListener != nullptr) {
+ char addrstr[INET6_ADDRSTRLEN];
+ char portstr[sizeof("65536")];
+ const int ret = getnameinfo((sockaddr*) &connectInfo.addr, sizeof(connectInfo.addr),
+ addrstr, sizeof(addrstr), portstr, sizeof(portstr),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+ netdEventListener->onConnectEvent(fwmark.netId, connectInfo.latencyMs,
+ (ret == 0) ? String16(addrstr) : String16(""),
+ (ret == 0) ? strtoul(portstr, NULL, 10) : 0, client->getUid());
+ }
+ break;
+ }
+
case FwmarkCommand::SELECT_NETWORK: {
fwmark.netId = command.netId;
if (command.netId == NETID_UNSET) {
diff --git a/server/FwmarkServer.h b/server/FwmarkServer.h
index 12096be..644acb8 100644
--- a/server/FwmarkServer.h
+++ b/server/FwmarkServer.h
@@ -17,13 +17,15 @@
#ifndef NETD_SERVER_FWMARK_SERVER_H
#define NETD_SERVER_FWMARK_SERVER_H
+#include "android/net/metrics/INetdEventListener.h"
+#include "EventReporter.h"
#include "sysutils/SocketListener.h"
class NetworkController;
class FwmarkServer : public SocketListener {
public:
- explicit FwmarkServer(NetworkController* networkController);
+ explicit FwmarkServer(NetworkController* networkController, EventReporter* eventReporter);
private:
// Overridden from SocketListener:
@@ -33,6 +35,7 @@
int processClient(SocketClient* client, int* socketFd);
NetworkController* const mNetworkController;
+ EventReporter* mEventReporter;
};
#endif // NETD_SERVER_FWMARK_SERVER_H
diff --git a/server/binder/android/net/metrics/INetdEventListener.aidl b/server/binder/android/net/metrics/INetdEventListener.aidl
index 5a5ed8f..49a20f2 100644
--- a/server/binder/android/net/metrics/INetdEventListener.aidl
+++ b/server/binder/android/net/metrics/INetdEventListener.aidl
@@ -48,4 +48,15 @@
*/
void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, String hostname,
in String[] ipAddresses, int ipAddressesCount, int uid);
+
+ /**
+ * Logs a single connect library call.
+ *
+ * @param netId the ID of the network the lookup was performed on.
+ * @param latencyMs the latency of the function call.
+ * @param ipAddr destination IP address.
+ * @param port destination port number.
+ * @param uid the UID of the application that performed the connection.
+ */
+ void onConnectEvent(int netId, int latencyMs, String ipAddr, int port, int uid);
}
diff --git a/server/main.cpp b/server/main.cpp
index da611cf..ae3a71a 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -99,7 +99,7 @@
exit(1);
}
- FwmarkServer fwmarkServer(&gCtls->netCtrl);
+ FwmarkServer fwmarkServer(&gCtls->netCtrl, &gCtls->eventReporter);
if (fwmarkServer.startListener()) {
ALOGE("Unable to start FwmarkServer (%s)", strerror(errno));
exit(1);