blob: b320b755f3f465c5990972dea8f2bc9527a67520 [file] [log] [blame]
Hugo Benichi0d4a3982016-11-25 11:24:22 +09001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.metrics;
18
Hugo Benichi5eb90532017-03-23 18:38:22 +090019import android.net.NetworkCapabilities;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090020import android.system.OsConstants;
21import android.util.IntArray;
22import android.util.SparseIntArray;
Hugo Benichiab209752017-09-27 23:28:59 +090023
Hugo Benichi5eb90532017-03-23 18:38:22 +090024import com.android.internal.util.BitUtils;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090025import com.android.internal.util.TokenBucket;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090026
27/**
Hugo Benichi5eb90532017-03-23 18:38:22 +090028 * A class that aggregates connect() statistics.
Hugo Benichi0d4a3982016-11-25 11:24:22 +090029 * {@hide}
30 */
31public class ConnectStats {
32 private final static int EALREADY = OsConstants.EALREADY;
33 private final static int EINPROGRESS = OsConstants.EINPROGRESS;
34
Hugo Benichi5eb90532017-03-23 18:38:22 +090035 /** Network id of the network associated with the event, or 0 if unspecified. */
36 public final int netId;
37 /** Transports of the network associated with the event, as defined in NetworkCapabilities. */
38 public final long transports;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090039 /** How many events resulted in a given errno. */
Hugo Benichi5eb90532017-03-23 18:38:22 +090040 public final SparseIntArray errnos = new SparseIntArray();
41 /** Latencies of successful blocking connects. TODO: add non-blocking connects latencies. */
42 public final IntArray latencies = new IntArray();
Hugo Benichi0d4a3982016-11-25 11:24:22 +090043 /** TokenBucket for rate limiting latency recording. */
Hugo Benichi5eb90532017-03-23 18:38:22 +090044 public final TokenBucket mLatencyTb;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090045 /** Maximum number of latency values recorded. */
Hugo Benichi5eb90532017-03-23 18:38:22 +090046 public final int mMaxLatencyRecords;
Hugo Benichiab209752017-09-27 23:28:59 +090047 /** Total count of events */
48 public int eventCount = 0;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090049 /** Total count of successful connects. */
Hugo Benichi5eb90532017-03-23 18:38:22 +090050 public int connectCount = 0;
Hugo Benichia2decca2017-02-22 14:32:27 +090051 /** Total count of successful connects done in blocking mode. */
Hugo Benichi5eb90532017-03-23 18:38:22 +090052 public int connectBlockingCount = 0;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090053 /** Total count of successful connects with IPv6 socket address. */
Hugo Benichi5eb90532017-03-23 18:38:22 +090054 public int ipv6ConnectCount = 0;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090055
Hugo Benichi5eb90532017-03-23 18:38:22 +090056 public ConnectStats(int netId, long transports, TokenBucket tb, int maxLatencyRecords) {
57 this.netId = netId;
58 this.transports = transports;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090059 mLatencyTb = tb;
60 mMaxLatencyRecords = maxLatencyRecords;
61 }
62
Hugo Benichiab209752017-09-27 23:28:59 +090063 boolean addEvent(int errno, int latencyMs, String ipAddr) {
64 eventCount++;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090065 if (isSuccess(errno)) {
Hugo Benichia2decca2017-02-22 14:32:27 +090066 countConnect(errno, ipAddr);
Hugo Benichi0d4a3982016-11-25 11:24:22 +090067 countLatency(errno, latencyMs);
Hugo Benichiab209752017-09-27 23:28:59 +090068 return true;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090069 } else {
70 countError(errno);
Hugo Benichiab209752017-09-27 23:28:59 +090071 return false;
Hugo Benichi0d4a3982016-11-25 11:24:22 +090072 }
73 }
74
Hugo Benichia2decca2017-02-22 14:32:27 +090075 private void countConnect(int errno, String ipAddr) {
Hugo Benichi5eb90532017-03-23 18:38:22 +090076 connectCount++;
Hugo Benichia2decca2017-02-22 14:32:27 +090077 if (!isNonBlocking(errno)) {
Hugo Benichi5eb90532017-03-23 18:38:22 +090078 connectBlockingCount++;
Hugo Benichia2decca2017-02-22 14:32:27 +090079 }
80 if (isIPv6(ipAddr)) {
Hugo Benichi5eb90532017-03-23 18:38:22 +090081 ipv6ConnectCount++;
Hugo Benichia2decca2017-02-22 14:32:27 +090082 }
Hugo Benichi0d4a3982016-11-25 11:24:22 +090083 }
84
85 private void countLatency(int errno, int ms) {
86 if (isNonBlocking(errno)) {
87 // Ignore connect() on non-blocking sockets
88 return;
89 }
90 if (!mLatencyTb.get()) {
91 // Rate limited
92 return;
93 }
Hugo Benichi5eb90532017-03-23 18:38:22 +090094 if (latencies.size() >= mMaxLatencyRecords) {
Hugo Benichi0d4a3982016-11-25 11:24:22 +090095 // Hard limit the total number of latency measurements.
96 return;
97 }
Hugo Benichi5eb90532017-03-23 18:38:22 +090098 latencies.add(ms);
Hugo Benichi0d4a3982016-11-25 11:24:22 +090099 }
100
101 private void countError(int errno) {
Hugo Benichi5eb90532017-03-23 18:38:22 +0900102 final int newcount = errnos.get(errno, 0) + 1;
103 errnos.put(errno, newcount);
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900104 }
105
106 private static boolean isSuccess(int errno) {
107 return (errno == 0) || isNonBlocking(errno);
108 }
109
Hugo Benichiab209752017-09-27 23:28:59 +0900110 static boolean isNonBlocking(int errno) {
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900111 // On non-blocking TCP sockets, connect() immediately returns EINPROGRESS.
112 // On non-blocking TCP sockets that are connecting, connect() immediately returns EALREADY.
113 return (errno == EINPROGRESS) || (errno == EALREADY);
114 }
115
116 private static boolean isIPv6(String ipAddr) {
117 return ipAddr.contains(":");
118 }
119
Hugo Benichia2decca2017-02-22 14:32:27 +0900120 @Override
121 public String toString() {
Hugo Benichic867f782017-11-07 21:42:10 +0900122 StringBuilder builder =
123 new StringBuilder("ConnectStats(").append("netId=").append(netId).append(", ");
Hugo Benichi5eb90532017-03-23 18:38:22 +0900124 for (int t : BitUtils.unpackBits(transports)) {
125 builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
126 }
Hugo Benichiab209752017-09-27 23:28:59 +0900127 builder.append(String.format("%d events, ", eventCount));
Hugo Benichi5eb90532017-03-23 18:38:22 +0900128 builder.append(String.format("%d success, ", connectCount));
129 builder.append(String.format("%d blocking, ", connectBlockingCount));
130 builder.append(String.format("%d IPv6 dst", ipv6ConnectCount));
131 for (int i = 0; i < errnos.size(); i++) {
132 String errno = OsConstants.errnoName(errnos.keyAt(i));
133 int count = errnos.valueAt(i);
Hugo Benichia2decca2017-02-22 14:32:27 +0900134 builder.append(String.format(", %s: %d", errno, count));
135 }
136 return builder.append(")").toString();
137 }
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900138}