TcpSocketMonitor: add polling loop
TcpSocketMonitor starts a sock_diag polling thread in its ctor whose
polling interval can be controlled with setPollingInterval() and
suspendPolling().
Initially the polling thread will immediately be suspended. The polling
thread is automatically started when 1 or more physical network exists,
and automatically stopped when there is 0 physical networks.
By default the polling interval is set to 30 secs.
Also fix some code indentation issues.
Bug: 64147860
Test: tested manually, watching the result of
$ adb shell dumpsys netd tcp_socket_info
Change-Id: I7fe356a0a073ebc83486bc774a3002648e9dd457
diff --git a/server/TcpSocketMonitor.cpp b/server/TcpSocketMonitor.cpp
index 3eb8014..2d53119 100644
--- a/server/TcpSocketMonitor.cpp
+++ b/server/TcpSocketMonitor.cpp
@@ -16,19 +16,25 @@
#define LOG_TAG "TcpSocketMonitor"
-#include "TcpSocketMonitor.h"
-#include "DumpWriter.h"
-
-#include "Fwmark.h"
-#include "SockDiag.h"
+#include <iomanip>
+#include <thread>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <linux/tcp.h>
+#include "DumpWriter.h"
+#include "Fwmark.h"
+#include "SockDiag.h"
+#include "TcpSocketMonitor.h"
+
namespace android {
namespace net {
+using std::chrono::duration_cast;
+using std::chrono::milliseconds;
+using std::chrono::steady_clock;
+
constexpr const char* getTcpStateName(int t) {
switch (t) {
case TCP_ESTABLISHED:
@@ -60,41 +66,48 @@
static void tcpInfoPrint(DumpWriter &dw, Fwmark mark, const struct inet_diag_msg *sockinfo,
const struct tcp_info *tcpinfo) {
- char saddr[INET6_ADDRSTRLEN] = {};
- char daddr[INET6_ADDRSTRLEN] = {};
- inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_src), saddr, sizeof(saddr));
- inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_dst), daddr, sizeof(daddr));
+ char saddr[INET6_ADDRSTRLEN] = {};
+ char daddr[INET6_ADDRSTRLEN] = {};
+ inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_src), saddr, sizeof(saddr));
+ inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_dst), daddr, sizeof(daddr));
- dw.println(
- "netId=%d uid=%u mark=0x%x saddr=%s daddr=%s sport=%u dport=%u tcp_state=%s(%u) "
- "rqueue=%u wqueue=%u rtt=%gms var_rtt=%gms rcv_rtt=%gms unacked=%u snd_cwnd=%u",
- mark.netId,
- sockinfo->idiag_uid,
- mark.intValue,
- saddr,
- daddr,
- ntohs(sockinfo->id.idiag_sport),
- ntohs(sockinfo->id.idiag_dport),
- getTcpStateName(sockinfo->idiag_state), sockinfo->idiag_state,
- sockinfo->idiag_rqueue,
- sockinfo->idiag_wqueue,
- tcpinfo != nullptr ? tcpinfo->tcpi_rtt/1000.0 : 0,
- tcpinfo != nullptr ? tcpinfo->tcpi_rttvar/1000.0 : 0,
- tcpinfo != nullptr ? tcpinfo->tcpi_rcv_rtt/1000.0 : 0,
- tcpinfo != nullptr ? tcpinfo->tcpi_unacked : 0,
- tcpinfo != nullptr ? tcpinfo->tcpi_snd_cwnd : 0);
+ dw.println(
+ "netId=%d uid=%u mark=0x%x saddr=%s daddr=%s sport=%u dport=%u tcp_state=%s(%u) "
+ "rqueue=%u wqueue=%u rtt=%gms var_rtt=%gms rcv_rtt=%gms unacked=%u snd_cwnd=%u",
+ mark.netId,
+ sockinfo->idiag_uid,
+ mark.intValue,
+ saddr,
+ daddr,
+ ntohs(sockinfo->id.idiag_sport),
+ ntohs(sockinfo->id.idiag_dport),
+ getTcpStateName(sockinfo->idiag_state), sockinfo->idiag_state,
+ sockinfo->idiag_rqueue,
+ sockinfo->idiag_wqueue,
+ tcpinfo != nullptr ? tcpinfo->tcpi_rtt/1000.0 : 0,
+ tcpinfo != nullptr ? tcpinfo->tcpi_rttvar/1000.0 : 0,
+ tcpinfo != nullptr ? tcpinfo->tcpi_rcv_rtt/1000.0 : 0,
+ tcpinfo != nullptr ? tcpinfo->tcpi_unacked : 0,
+ tcpinfo != nullptr ? tcpinfo->tcpi_snd_cwnd : 0);
}
const String16 TcpSocketMonitor::DUMP_KEYWORD = String16("tcp_socket_info");
+const milliseconds TcpSocketMonitor::kDefaultPollingInterval = milliseconds(30000);
void TcpSocketMonitor::dump(DumpWriter& dw) {
+ std::lock_guard<std::mutex> guard(mLock);
+
dw.println("TcpSocketMonitor");
dw.incIndent();
+ const auto now = steady_clock::now();
+ const auto d = duration_cast<milliseconds>(now - mLastPoll);
+ dw.println("last poll %lld ms ago", d.count());
+
SockDiag sd;
if (!sd.open()) {
- ALOGE("Error opening sock diag for dumping TCP socket info");
- return;
+ ALOGE("Error opening sock diag for dumping TCP socket info");
+ return;
}
const auto tcpInfoReader = [&dw](Fwmark mark, const struct inet_diag_msg *sockinfo,
@@ -110,5 +123,117 @@
dw.decIndent();
}
+void TcpSocketMonitor::setPollingInterval(milliseconds nextSleepDurationMs) {
+ std::lock_guard<std::mutex> guard(mLock);
+
+ mNextSleepDurationMs = nextSleepDurationMs;
+
+ ALOGD("tcpinfo polling interval set to %lld ms", mNextSleepDurationMs.count());
+}
+
+void TcpSocketMonitor::resumePolling() {
+ {
+ std::lock_guard<std::mutex> guard(mLock);
+
+ if (!mIsSuspended) {
+ return;
+ }
+
+ mIsSuspended = false;
+
+ ALOGD("resuming tcpinfo polling with polling interval set to %lld ms",
+ mNextSleepDurationMs.count());
+ }
+
+ mCv.notify_all();
+}
+
+void TcpSocketMonitor::suspendPolling() {
+ std::lock_guard<std::mutex> guard(mLock);
+
+ if (!mIsSuspended) {
+ ALOGD("suspending tcpinfo polling");
+ mIsSuspended = true;
+ }
+}
+
+void TcpSocketMonitor::poll() {
+ std::lock_guard<std::mutex> guard(mLock);
+
+ if (mIsSuspended) {
+ return;
+ }
+
+ const auto now = steady_clock::now();
+
+ SockDiag sd;
+ if (!sd.open()) {
+ ALOGE("Error opening sock diag for polling TCP socket info");
+ return;
+ }
+
+ const auto tcpInfoReader = [](Fwmark mark, const struct inet_diag_msg *sockinfo,
+ const struct tcp_info *tcpinfo) {
+ if (sockinfo == nullptr || tcpinfo == nullptr || mark.intValue == 0) {
+ return;
+ }
+
+ // TODO: process socket stats
+ };
+
+ if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
+ ALOGE("Failed to poll TCP socket info: %s", strerror(-ret));
+ return;
+ }
+
+ mLastPoll = now;
+}
+
+void TcpSocketMonitor::waitForNextPoll() {
+ bool isSuspended;
+ milliseconds nextSleepDurationMs;
+ {
+ std::lock_guard<std::mutex> guard(mLock);
+ isSuspended = mIsSuspended;
+ nextSleepDurationMs= mNextSleepDurationMs;
+ }
+
+ std::unique_lock<std::mutex> ul(mLock);
+ if (isSuspended) {
+ mCv.wait(ul);
+ } else {
+ mCv.wait_for(ul, nextSleepDurationMs);
+ }
+}
+
+bool TcpSocketMonitor::isRunning() {
+ std::lock_guard<std::mutex> guard(mLock);
+ return mIsRunning;
+}
+
+TcpSocketMonitor::TcpSocketMonitor() {
+ std::lock_guard<std::mutex> guard(mLock);
+
+ mNextSleepDurationMs = kDefaultPollingInterval;
+ mIsSuspended = true;
+ mIsRunning = true;
+ mPollingThread = std::thread([this] {
+ while (isRunning()) {
+ poll();
+ waitForNextPoll();
+ }
+ });
+}
+
+TcpSocketMonitor::~TcpSocketMonitor() {
+ {
+ std::lock_guard<std::mutex> guard(mLock);
+ mIsRunning = false;
+ mIsSuspended = true;
+ }
+ mCv.notify_all();
+ mPollingThread.join();
+}
+
} // namespace net
} // namespace android